Compare commits

..

5 Commits

Author SHA1 Message Date
37ac7576f1 Docs: Updated instructions on importing third-party packages to Sandbox (#9890)
### What problem does this PR solve?


### Type of change

- [x] Documentation Update
2025-09-03 15:47:07 +08:00
c832e0b858 Feat: add canvas_category field for UserCanvas and CanvasTemplate (#9885)
### What problem does this PR solve?

Add `canvas_category` field for UserCanvas and CanvasTemplate.

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
2025-09-03 14:55:24 +08:00
5d015e48c1 Docs: Updated the Code component reference (#9884)
### What problem does this PR solve?


### Type of change

- [x] Documentation Update
2025-09-03 14:23:03 +08:00
b58e882eaa Feat: add exponential back-off for Chat LiteLLM (#9880)
### What problem does this PR solve?

Add exponential back-off for Chat LiteLLM. #9858.

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
2025-09-03 13:31:43 +08:00
1bc33009c7 Fix: The operator added by clicking the plus sign will overlap with the original operator. #9886 (#9887)
### What problem does this PR solve?

Fix: The operator added by clicking the plus sign will overlap with the
original operator. #9886

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
2025-09-03 13:03:23 +08:00
11 changed files with 227 additions and 50 deletions

View File

@ -24,7 +24,7 @@ from flask import request, Response
from flask_login import login_required, current_user from flask_login import login_required, current_user
from agent.component import LLM from agent.component import LLM
from api.db import FileType from api.db import CanvasCategory, FileType
from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService, API4ConversationService from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService, API4ConversationService
from api.db.services.document_service import DocumentService from api.db.services.document_service import DocumentService
from api.db.services.file_service import FileService from api.db.services.file_service import FileService
@ -45,14 +45,14 @@ from rag.utils.redis_conn import REDIS_CONN
@manager.route('/templates', methods=['GET']) # noqa: F821 @manager.route('/templates', methods=['GET']) # noqa: F821
@login_required @login_required
def templates(): def templates():
return get_json_result(data=[c.to_dict() for c in CanvasTemplateService.get_all()]) return get_json_result(data=[c.to_dict() for c in CanvasTemplateService.query(canvas_category=CanvasCategory.Agent)])
@manager.route('/list', methods=['GET']) # noqa: F821 @manager.route('/list', methods=['GET']) # noqa: F821
@login_required @login_required
def canvas_list(): def canvas_list():
return get_json_result(data=sorted([c.to_dict() for c in \ return get_json_result(data=sorted([c.to_dict() for c in \
UserCanvasService.query(user_id=current_user.id)], key=lambda x: x["update_time"]*-1) UserCanvasService.query(user_id=current_user.id, canvas_category=CanvasCategory.Agent)], key=lambda x: x["update_time"]*-1)
) )
@ -79,7 +79,7 @@ def save():
req["dsl"] = json.loads(req["dsl"]) req["dsl"] = json.loads(req["dsl"])
if "id" not in req: if "id" not in req:
req["user_id"] = current_user.id req["user_id"] = current_user.id
if UserCanvasService.query(user_id=current_user.id, title=req["title"].strip()): if UserCanvasService.query(user_id=current_user.id, title=req["title"].strip(), canvas_category=CanvasCategory.Agent):
return get_data_error_result(message=f"{req['title'].strip()} already exists.") return get_data_error_result(message=f"{req['title'].strip()} already exists.")
req["id"] = get_uuid() req["id"] = get_uuid()
if not UserCanvasService.save(**req): if not UserCanvasService.save(**req):
@ -395,7 +395,7 @@ def list_canvas():
tenants = TenantService.get_joined_tenants_by_user_id(current_user.id) tenants = TenantService.get_joined_tenants_by_user_id(current_user.id)
canvas, total = UserCanvasService.get_by_tenant_ids( canvas, total = UserCanvasService.get_by_tenant_ids(
[m["tenant_id"] for m in tenants], current_user.id, page_number, [m["tenant_id"] for m in tenants], current_user.id, page_number,
items_per_page, orderby, desc, keywords) items_per_page, orderby, desc, keywords, canvas_category=CanvasCategory.Agent)
return get_json_result(data={"canvas": canvas, "total": total}) return get_json_result(data={"canvas": canvas, "total": total})
except Exception as e: except Exception as e:
return server_error_response(e) return server_error_response(e)

View File

@ -74,8 +74,10 @@ class TaskStatus(StrEnum):
DONE = "3" DONE = "3"
FAIL = "4" FAIL = "4"
VALID_TASK_STATUS = {TaskStatus.UNSTART, TaskStatus.RUNNING, TaskStatus.CANCEL, TaskStatus.DONE, TaskStatus.FAIL} VALID_TASK_STATUS = {TaskStatus.UNSTART, TaskStatus.RUNNING, TaskStatus.CANCEL, TaskStatus.DONE, TaskStatus.FAIL}
class ParserType(StrEnum): class ParserType(StrEnum):
PRESENTATION = "presentation" PRESENTATION = "presentation"
LAWS = "laws" LAWS = "laws"
@ -105,10 +107,19 @@ class CanvasType(StrEnum):
DocBot = "docbot" DocBot = "docbot"
class CanvasCategory(StrEnum):
Agent = "agent_canvas"
DataFlow = "dataflow_canvas"
VALID_CAVAS_CATEGORIES = {CanvasCategory.Agent, CanvasCategory.DataFlow}
class MCPServerType(StrEnum): class MCPServerType(StrEnum):
SSE = "sse" SSE = "sse"
STREAMABLE_HTTP = "streamable-http" STREAMABLE_HTTP = "streamable-http"
VALID_MCP_SERVER_TYPES = {MCPServerType.SSE, MCPServerType.STREAMABLE_HTTP} VALID_MCP_SERVER_TYPES = {MCPServerType.SSE, MCPServerType.STREAMABLE_HTTP}
KNOWLEDGEBASE_FOLDER_NAME=".knowledgebase" KNOWLEDGEBASE_FOLDER_NAME=".knowledgebase"

View File

@ -245,20 +245,19 @@ class JsonSerializedField(SerializedField):
class RetryingPooledMySQLDatabase(PooledMySQLDatabase): class RetryingPooledMySQLDatabase(PooledMySQLDatabase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.max_retries = kwargs.pop('max_retries', 5) self.max_retries = kwargs.pop("max_retries", 5)
self.retry_delay = kwargs.pop('retry_delay', 1) self.retry_delay = kwargs.pop("retry_delay", 1)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def execute_sql(self, sql, params=None, commit=True): def execute_sql(self, sql, params=None, commit=True):
from peewee import OperationalError from peewee import OperationalError
for attempt in range(self.max_retries + 1): for attempt in range(self.max_retries + 1):
try: try:
return super().execute_sql(sql, params, commit) return super().execute_sql(sql, params, commit)
except OperationalError as e: except OperationalError as e:
if e.args[0] in (2013, 2006) and attempt < self.max_retries: if e.args[0] in (2013, 2006) and attempt < self.max_retries:
logging.warning( logging.warning(f"Lost connection (attempt {attempt + 1}/{self.max_retries}): {e}")
f"Lost connection (attempt {attempt+1}/{self.max_retries}): {e}"
)
self._handle_connection_loss() self._handle_connection_loss()
time.sleep(self.retry_delay * (2**attempt)) time.sleep(self.retry_delay * (2**attempt))
else: else:
@ -272,14 +271,13 @@ class RetryingPooledMySQLDatabase(PooledMySQLDatabase):
def begin(self): def begin(self):
from peewee import OperationalError from peewee import OperationalError
for attempt in range(self.max_retries + 1): for attempt in range(self.max_retries + 1):
try: try:
return super().begin() return super().begin()
except OperationalError as e: except OperationalError as e:
if e.args[0] in (2013, 2006) and attempt < self.max_retries: if e.args[0] in (2013, 2006) and attempt < self.max_retries:
logging.warning( logging.warning(f"Lost connection during transaction (attempt {attempt + 1}/{self.max_retries})")
f"Lost connection during transaction (attempt {attempt+1}/{self.max_retries})"
)
self._handle_connection_loss() self._handle_connection_loss()
time.sleep(self.retry_delay * (2**attempt)) time.sleep(self.retry_delay * (2**attempt))
else: else:
@ -815,6 +813,7 @@ class UserCanvas(DataBaseModel):
permission = CharField(max_length=16, null=False, help_text="me|team", default="me", index=True) permission = CharField(max_length=16, null=False, help_text="me|team", default="me", index=True)
description = TextField(null=True, help_text="Canvas description") description = TextField(null=True, help_text="Canvas description")
canvas_type = CharField(max_length=32, null=True, help_text="Canvas type", index=True) canvas_type = CharField(max_length=32, null=True, help_text="Canvas type", index=True)
canvas_category = CharField(max_length=32, null=False, default="agent_canvas", help_text="Canvas category: agent_canvas|dataflow_canvas", index=True)
dsl = JSONField(null=True, default={}) dsl = JSONField(null=True, default={})
class Meta: class Meta:
@ -827,6 +826,7 @@ class CanvasTemplate(DataBaseModel):
title = JSONField(null=True, default=dict, help_text="Canvas title") title = JSONField(null=True, default=dict, help_text="Canvas title")
description = JSONField(null=True, default=dict, help_text="Canvas description") description = JSONField(null=True, default=dict, help_text="Canvas description")
canvas_type = CharField(max_length=32, null=True, help_text="Canvas type", index=True) canvas_type = CharField(max_length=32, null=True, help_text="Canvas type", index=True)
canvas_category = CharField(max_length=32, null=False, default="agent_canvas", help_text="Canvas category: agent_canvas|dataflow_canvas", index=True)
dsl = JSONField(null=True, default={}) dsl = JSONField(null=True, default={})
class Meta: class Meta:
@ -1029,4 +1029,12 @@ def migrate_db():
migrate(migrator.alter_column_type("canvas_template", "description", JSONField(null=True, default=dict, help_text="Canvas description"))) migrate(migrator.alter_column_type("canvas_template", "description", JSONField(null=True, default=dict, help_text="Canvas description")))
except Exception: except Exception:
pass pass
try:
migrate(migrator.add_column("user_canvas", "canvas_category", CharField(max_length=32, null=False, default="agent_canvas", help_text="agent_canvas|dataflow_canvas", index=True)))
except Exception:
pass
try:
migrate(migrator.add_column("canvas_template", "canvas_category", CharField(max_length=32, null=False, default="agent_canvas", help_text="agent_canvas|dataflow_canvas", index=True)))
except Exception:
pass
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)

View File

@ -18,7 +18,7 @@ import logging
import time import time
from uuid import uuid4 from uuid import uuid4
from agent.canvas import Canvas from agent.canvas import Canvas
from api.db import TenantPermission from api.db import CanvasCategory, TenantPermission
from api.db.db_models import DB, CanvasTemplate, User, UserCanvas, API4Conversation from api.db.db_models import DB, CanvasTemplate, User, UserCanvas, API4Conversation
from api.db.services.api_service import API4ConversationService from api.db.services.api_service import API4ConversationService
from api.db.services.common_service import CommonService from api.db.services.common_service import CommonService
@ -31,6 +31,12 @@ from peewee import fn
class CanvasTemplateService(CommonService): class CanvasTemplateService(CommonService):
model = CanvasTemplate model = CanvasTemplate
class DataFlowTemplateService(CommonService):
"""
Alias of CanvasTemplateService
"""
model = CanvasTemplate
class UserCanvasService(CommonService): class UserCanvasService(CommonService):
model = UserCanvas model = UserCanvas
@ -38,13 +44,14 @@ class UserCanvasService(CommonService):
@classmethod @classmethod
@DB.connection_context() @DB.connection_context()
def get_list(cls, tenant_id, def get_list(cls, tenant_id,
page_number, items_per_page, orderby, desc, id, title): page_number, items_per_page, orderby, desc, id, title, canvas_category=CanvasCategory.Agent):
agents = cls.model.select() agents = cls.model.select()
if id: if id:
agents = agents.where(cls.model.id == id) agents = agents.where(cls.model.id == id)
if title: if title:
agents = agents.where(cls.model.title == title) agents = agents.where(cls.model.title == title)
agents = agents.where(cls.model.user_id == tenant_id) agents = agents.where(cls.model.user_id == tenant_id)
agents = agents.where(cls.model.canvas_category == canvas_category)
if desc: if desc:
agents = agents.order_by(cls.model.getter_by(orderby).desc()) agents = agents.order_by(cls.model.getter_by(orderby).desc())
else: else:
@ -71,6 +78,7 @@ class UserCanvasService(CommonService):
cls.model.create_time, cls.model.create_time,
cls.model.create_date, cls.model.create_date,
cls.model.update_date, cls.model.update_date,
cls.model.canvas_category,
User.nickname, User.nickname,
User.avatar.alias('tenant_avatar'), User.avatar.alias('tenant_avatar'),
] ]
@ -87,7 +95,7 @@ class UserCanvasService(CommonService):
@DB.connection_context() @DB.connection_context()
def get_by_tenant_ids(cls, joined_tenant_ids, user_id, def get_by_tenant_ids(cls, joined_tenant_ids, user_id,
page_number, items_per_page, page_number, items_per_page,
orderby, desc, keywords, orderby, desc, keywords, canvas_category=CanvasCategory.Agent,
): ):
fields = [ fields = [
cls.model.id, cls.model.id,
@ -98,7 +106,8 @@ class UserCanvasService(CommonService):
cls.model.permission, cls.model.permission,
User.nickname, User.nickname,
User.avatar.alias('tenant_avatar'), User.avatar.alias('tenant_avatar'),
cls.model.update_time cls.model.update_time,
cls.model.canvas_category,
] ]
if keywords: if keywords:
agents = cls.model.select(*fields).join(User, on=(cls.model.user_id == User.id)).where( agents = cls.model.select(*fields).join(User, on=(cls.model.user_id == User.id)).where(
@ -113,6 +122,7 @@ class UserCanvasService(CommonService):
TenantPermission.TEAM.value)) | ( TenantPermission.TEAM.value)) | (
cls.model.user_id == user_id)) cls.model.user_id == user_id))
) )
agents = agents.where(cls.model.canvas_category == canvas_category)
if desc: if desc:
agents = agents.order_by(cls.model.getter_by(orderby).desc()) agents = agents.order_by(cls.model.getter_by(orderby).desc())
else: else:

View File

@ -13,6 +13,32 @@ A component that enables users to integrate Python or JavaScript codes into thei
A **Code** component is essential when you need to integrate complex code logic (Python or JavaScript) into your Agent for dynamic data processing. A **Code** component is essential when you need to integrate complex code logic (Python or JavaScript) into your Agent for dynamic data processing.
## Prerequisites
### 1. Ensure gVisor is properly installed
We use gVisor to isolate code execution from the host system. Please follow [the official installation guide](https://gvisor.dev/docs/user_guide/install/) to install gVisor, ensuring your operating system is compatible before proceeding.
### 2. Ensure Sandbox is properly installed
RAGFlow Sandbox is a secure, pluggable code execution backend. It serves as the code executor for the **Code** component. Please follow the [instructions here](https://github.com/infiniflow/ragflow/tree/main/sandbox) to install RAGFlow Sandbox.
:::tip NOTE
If your RAGFlow Sandbox is not working, please be sure to consult the [Troubleshooting](#troubleshooting) section in this document. We assure you that it addresses 99.99% of the issues!
:::
### 3. (Optional) Install necessary dependencies
If you need to import your own Python or JavaScript packages into Sandbox, please follow the commands provided in the [How to import my own Python or JavaScript packages into Sandbox?](#how-to-import-my-own-python-or-javascript-packages-into-sandbox) section to install the additional dependencies.
### 4. Enable Sandbox-specific settings in RAGFlow
Ensure all Sandbox-specific settings are enabled in **ragflow/docker/.env**.
### 5. Restart the service after making changes
Any changes to the configuration or environment *require* a full service restart to take effect.
## Configurations ## Configurations
### Input ### Input
@ -55,4 +81,112 @@ You define the output variable(s) of the **Code** component here.
The defined output variable(s) will be auto-populated here. The defined output variable(s) will be auto-populated here.
## Troubleshooting
### `HTTPConnectionPool(host='sandbox-executor-manager', port=9385): Read timed out.`
**Root cause**
- You did not properly install gVisor and `runsc` was not recognized as a valid Docker runtime.
- You did not pull the required base images for the runners and no runner was started.
**Solution**
For the gVisor issue:
1. Install [gVisor](https://gvisor.dev/docs/user_guide/install/).
2. Restart Docker.
3. Run the following to double check:
```bash
docker run --rm --runtime=runsc hello-world
```
For the base image issue, pull the required base images:
```bash
docker pull infiniflow/sandbox-base-nodejs:latest
docker pull infiniflow/sandbox-base-python:latest
```
### `HTTPConnectionPool(host='none', port=9385): Max retries exceeded.`
**Root cause**
`sandbox-executor-manager` is not mapped in `/etc/hosts`.
**Solution**
Add a new entry to `/etc/hosts`:
`127.0.0.1 es01 infinity mysql minio redis sandbox-executor-manager`
### `Container pool is busy`
**Root cause**
All runners are currently in use, executing tasks.
**Solution**
Please try again shortly or increase the pool size in the configuration to improve availability and reduce waiting times.
## Frequently asked questions
### How to import my own Python or JavaScript packages into Sandbox?
To import your Python packages, update **sandbox_base_image/python/requirements.txt** to install the required dependencies. For example, to add the `openpyxl` package, proceed with the following command lines:
```bash {4,6}
(ragflow) ➜ ragflow/sandbox main ✓ pwd # make sure you are in the right directory
/home/infiniflow/workspace/ragflow/sandbox
(ragflow) ➜ ragflow/sandbox main ✓ echo "openpyxl" >> sandbox_base_image/python/requirements.txt # add the package to the requirements.txt file
(ragflow) ➜ ragflow/sandbox main ✗ cat sandbox_base_image/python/requirements.txt # make sure the package is added
numpy
pandas
requests
openpyxl # here it is
(ragflow) ➜ ragflow/sandbox main ✗ make # rebuild the docker image, this command will rebuild the iamge and start the service immediately. To build image only, using `make build` instead.
(ragflow) ➜ ragflow/sandbox main ✗ docker exec -it sandbox_python_0 /bin/bash # entering container to check if the package is installed
# in the container
nobody@ffd8a7dd19da:/workspace$ python # launch python shell
Python 3.11.13 (main, Aug 12 2025, 22:46:03) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import openpyxl # import the package to verify installation
>>>
# That's okay!
```
To import your JavaScript packages, navigate to `sandbox_base_image/nodejs` and use `npm` to install the required packages. For example, to add the `lodash` package, run the following commands:
```bash
(ragflow) ➜ ragflow/sandbox main ✓ pwd
/home/infiniflow/workspace/ragflow/sandbox
(ragflow) ➜ ragflow/sandbox main ✓ cd sandbox_base_image/nodejs
(ragflow) ➜ ragflow/sandbox/sandbox_base_image/nodejs main ✓ npm install lodash
(ragflow) ➜ ragflow/sandbox/sandbox_base_image/nodejs main ✓ cd ../.. # go back to sandbox root directory
(ragflow) ➜ ragflow/sandbox main ✗ make # rebuild the docker image, this command will rebuild the iamge and start the service immediately. To build image only, using `make build` instead.
(ragflow) ➜ ragflow/sandbox main ✗ docker exec -it sandbox_nodejs_0 /bin/bash # entering container to check if the package is installed
# in the container
nobody@dd4bbcabef63:/workspace$ npm list lodash # verify via npm list
/workspace
`-- lodash@4.17.21 extraneous
nobody@dd4bbcabef63:/workspace$ ls node_modules | grep lodash # or verify via listing node_modules
lodash
# That's okay!
```

View File

@ -27,7 +27,7 @@ The corresponding configuration panel appears to the right of the canvas. Use th
### 2. Input query variable(s) ### 2. Input query variable(s)
The **Retrieval** component relies on query variables to specify its queries. The **Retrieval** component depends on query variables to specify its queries.
:::caution IMPORTANT :::caution IMPORTANT
- If you use the **Retrieval** component as a standalone workflow module, input query variables in the **Input Variables** text box. - If you use the **Retrieval** component as a standalone workflow module, input query variables in the **Input Variables** text box.
@ -42,7 +42,7 @@ You can specify one or multiple knowledge bases to retrieve data from. If select
### 4. Expand **Advanced Settings** to configure the retrieval method ### 4. Expand **Advanced Settings** to configure the retrieval method
By default, a combination of weighted keyword similarity and weighted vector cosine similarity is used during retrieval. If a rerank model is selected, a combination of weighted keyword similarity and weighted reranking score will be used for retrieval. By default, a combination of weighted keyword similarity and weighted vector cosine similarity is used for retrieval. If a rerank model is selected, a combination of weighted keyword similarity and weighted reranking score will be used instead.
As a starter, you can skip this step to stay with the default retrieval method. As a starter, you can skip this step to stay with the default retrieval method.
@ -57,9 +57,9 @@ If your user query is different from the languages of the knowledge bases, you c
### 6. Test retrieval results ### 6. Test retrieval results
Click the triangle button on the top of canvas to test the retrieval results. Click the **Run** button on the top of canvas to test the retrieval results.
### 6. Choose the next component ### 7. Choose the next component
When necessary, click the **+** button on the **Retrieval** component to choose the next component in the worflow from the dropdown list. When necessary, click the **+** button on the **Retrieval** component to choose the next component in the worflow from the dropdown list.

View File

@ -1534,6 +1534,7 @@ class LiteLLMBase(ABC):
"model": self.model_name, "model": self.model_name,
"messages": history, "messages": history,
"api_key": self.api_key, "api_key": self.api_key,
"num_retries": self.max_retries,
**kwargs, **kwargs,
} }
if stream: if stream:

View File

@ -24,3 +24,5 @@ export enum AgentGlobals {
SysConversationTurns = 'sys.conversation_turns', SysConversationTurns = 'sys.conversation_turns',
SysFiles = 'sys.files', SysFiles = 'sys.files',
} }
export const AgentGlobalsSysQueryWithBrace = `{${AgentGlobals.SysQuery}}`;

View File

@ -225,6 +225,14 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) {
}; };
const OnConnectEnd = (event: MouseEvent | TouchEvent) => { const OnConnectEnd = (event: MouseEvent | TouchEvent) => {
const target = event.target as HTMLElement;
// Clicking Handle will also trigger OnConnectEnd.
// To solve the problem that the operator on the right side added by clicking Handle will overlap with the original operator, this event is blocked here.
// TODO: However, a better way is to add both operators in the same way as OnConnectEnd.
if (target?.classList.contains('react-flow__handle')) {
return;
}
if ('clientX' in event && 'clientY' in event) { if ('clientX' in event && 'clientY' in event) {
const { clientX, clientY } = event; const { clientX, clientY } = event;
setDropdownPosition({ x: clientX, y: clientY }); setDropdownPosition({ x: clientX, y: clientY });

View File

@ -55,7 +55,9 @@ function OperatorItemList({
const onNodeCreated = useContext(OnNodeCreatedContext); const onNodeCreated = useContext(OnNodeCreatedContext);
const { t } = useTranslation(); const { t } = useTranslation();
const handleClick = (operator: Operator) => { const handleClick =
(operator: Operator): React.MouseEventHandler<HTMLElement> =>
(e) => {
const contextData = handleContext || { const contextData = handleContext || {
nodeId: '', nodeId: '',
id: '', id: '',
@ -69,7 +71,7 @@ function OperatorItemList({
clientX: mousePosition.x, clientX: mousePosition.x,
clientY: mousePosition.y, clientY: mousePosition.y,
} }
: undefined; : e;
const newNodeId = addCanvasNode(operator, contextData)(mockEvent); const newNodeId = addCanvasNode(operator, contextData)(mockEvent);
@ -92,12 +94,12 @@ function OperatorItemList({
<Tooltip key={operator}> <Tooltip key={operator}>
<TooltipTrigger asChild> <TooltipTrigger asChild>
{isCustomDropdown ? ( {isCustomDropdown ? (
<li onClick={() => handleClick(operator)}>{commonContent}</li> <li onClick={handleClick(operator)}>{commonContent}</li>
) : ( ) : (
<DropdownMenuItem <DropdownMenuItem
key={operator} key={operator}
className="hover:bg-background-card py-1 px-3 cursor-pointer rounded-sm flex gap-2 items-center justify-start" className="hover:bg-background-card py-1 px-3 cursor-pointer rounded-sm flex gap-2 items-center justify-start"
onClick={() => handleClick(operator)} onClick={handleClick(operator)}
onSelect={() => hideModal?.()} onSelect={() => hideModal?.()}
> >
<OperatorIcon name={operator} /> <OperatorIcon name={operator} />

View File

@ -4,6 +4,7 @@ import {
} from '@/components/similarity-slider'; } from '@/components/similarity-slider';
import { import {
AgentGlobals, AgentGlobals,
AgentGlobalsSysQueryWithBrace,
CodeTemplateStrMap, CodeTemplateStrMap,
ProgrammingLanguage, ProgrammingLanguage,
} from '@/constants/agent'; } from '@/constants/agent';
@ -247,7 +248,7 @@ const initialQueryBaseValues = {
}; };
export const initialRetrievalValues = { export const initialRetrievalValues = {
query: AgentGlobals.SysQuery, query: AgentGlobalsSysQueryWithBrace,
top_n: 8, top_n: 8,
top_k: 1024, top_k: 1024,
kb_ids: [], kb_ids: [],