Commit 4ee790db by Xianquan Committed by GitHub

refactor: migrate community config to env vars (#7200)

* refactor: migrate community config to env vars

* test: fix sandbox proxy env fixture

---------

Co-authored-by: Archer <545436317@qq.com>
parent 03ff1b5d
...@@ -196,12 +196,37 @@ ${{vec.db}} ...@@ -196,12 +196,37 @@ ${{vec.db}}
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: ${{fastgpt-code-sandbox.image}}:${{fastgpt-code-sandbox.tag}} image: ${{fastgpt-code-sandbox.image}}:${{fastgpt-code-sandbox.tag}}
......
...@@ -253,12 +253,37 @@ services: ...@@ -253,12 +253,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1 image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -231,12 +231,37 @@ services: ...@@ -231,12 +231,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1 image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -215,12 +215,37 @@ services: ...@@ -215,12 +215,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1 image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -213,12 +213,37 @@ services: ...@@ -213,12 +213,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1 image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -218,12 +218,37 @@ services: ...@@ -218,12 +218,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1 image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -197,12 +197,37 @@ services: ...@@ -197,12 +197,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1 image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -253,12 +253,37 @@ services: ...@@ -253,12 +253,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1 image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -231,12 +231,37 @@ services: ...@@ -231,12 +231,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1 image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -215,12 +215,37 @@ services: ...@@ -215,12 +215,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1 image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -213,12 +213,37 @@ services: ...@@ -213,12 +213,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1 image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -218,12 +218,37 @@ services: ...@@ -218,12 +218,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1 image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -197,12 +197,37 @@ services: ...@@ -197,12 +197,37 @@ services:
AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000 AIPROXY_API_ENDPOINT: http://fastgpt-aiproxy:3000
# AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY # AI Proxy 的 Admin Token,与 AI Proxy 中的环境变量 ADMIN_KEY
AIPROXY_API_TOKEN: *x-aiproxy-token AIPROXY_API_TOKEN: *x-aiproxy-token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址
MCP_SERVER_PROXY_ENDPOINT:
# ==================== 原 config.json systemEnv 配置 ====================
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS: 10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS: 10
# 问答拆分队列最大并发数
QA_MAX_PROCESS: 10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS: 10
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH: 100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES: 100000
# 自定义 PDF 解析服务配置
CUSTOM_PDF_PARSE_URL:
CUSTOM_PDF_PARSE_KEY:
DOC2X_KEY:
TEXTIN_APP_ID:
TEXTIN_SECRET_CODE:
CUSTOM_PDF_PARSE_PRICE: 0
# 文件 URL 白名单,逗号或空白分隔
FILE_URL_WHITELIST:
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: false
# ==================== 日志与监控 ==================== # ==================== 日志与监控 ====================
# 传递给 OTLP 收集器的服务名称 # 传递给 OTLP 收集器的服务名称
LOG_OTEL_SERVICE_NAME: fastgpt-client LOG_OTEL_SERVICE_NAME: fastgpt-client
volumes:
- ./config.json:/app/data/config.json
fastgpt-code-sandbox: fastgpt-code-sandbox:
container_name: fastgpt-code-sandbox container_name: fastgpt-code-sandbox
image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1 image: ghcr.io/labring/fastgpt-code-sandbox:v4.15.0-beta1
......
...@@ -273,7 +273,6 @@ if [ "$REGION" == "global" ] && [ "$VECTOR" == "zilliz" ]; then ...@@ -273,7 +273,6 @@ if [ "$REGION" == "global" ] && [ "$VECTOR" == "zilliz" ]; then
fi fi
YML_URL="${BASE_URL}/docker/${DEPLOY_VERSION}/${REGION}/docker-compose.${VECTOR_FILE}.yml" YML_URL="${BASE_URL}/docker/${DEPLOY_VERSION}/${REGION}/docker-compose.${VECTOR_FILE}.yml"
CONFIG_URL="${BASE_URL}/config/config.json" CONFIG_URL="${BASE_URL}/config/config.json"
# 下载 docker-compose YAML # 下载 docker-compose YAML
...@@ -285,13 +284,18 @@ fi ...@@ -285,13 +284,18 @@ fi
mv "docker-compose.${VECTOR_FILE}.yml" docker-compose.yml mv "docker-compose.${VECTOR_FILE}.yml" docker-compose.yml
echo "已下载 docker-compose.yml" echo "已下载 docker-compose.yml"
# 下载 config.json USES_CONFIG_JSON=false
curl -fsSL -O "$CONFIG_URL" if LC_ALL=C grep -q -- "./config.json:/app/data/config.json" docker-compose.yml; then
if [ $? -ne 0 ]; then USES_CONFIG_JSON=true
echo "错误: 下载 config.json 失败: $CONFIG_URL"
exit 1 # 下载旧版本 docker-compose 仍挂载的 config.json。
curl -fsSL -O "$CONFIG_URL"
if [ $? -ne 0 ]; then
echo "错误: 下载 config.json 失败: $CONFIG_URL"
exit 1
fi
echo "已下载 config.json"
fi fi
echo "已下载 config.json"
# ========== 替换 S3 访问地址 ========== # ========== 替换 S3 访问地址 ==========
if [ -n "$S3_ADDR" ]; then if [ -n "$S3_ADDR" ]; then
...@@ -354,19 +358,27 @@ if [ -n "$MCP_ADDR" ]; then ...@@ -354,19 +358,27 @@ if [ -n "$MCP_ADDR" ]; then
MCP_ENDPOINT="http://$MCP_ADDR:3003" MCP_ENDPOINT="http://$MCP_ADDR:3003"
fi fi
if [[ "$OSTYPE" == "darwin"* ]]; then if $USES_CONFIG_JSON; then
sed -i '' "s|\"mcpServerProxyEndpoint\": \"\"|\"mcpServerProxyEndpoint\": \"$MCP_ENDPOINT\"|g" config.json if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s|\"mcpServerProxyEndpoint\": \"\"|\"mcpServerProxyEndpoint\": \"$MCP_ENDPOINT\"|g" config.json
else
sed -i "s|\"mcpServerProxyEndpoint\": \"\"|\"mcpServerProxyEndpoint\": \"$MCP_ENDPOINT\"|g" config.json
fi
else else
sed -i "s|\"mcpServerProxyEndpoint\": \"\"|\"mcpServerProxyEndpoint\": \"$MCP_ENDPOINT\"|g" config.json if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s|^ MCP_SERVER_PROXY_ENDPOINT:.*| MCP_SERVER_PROXY_ENDPOINT: $MCP_ENDPOINT|g" docker-compose.yml
else
sed -i "s|^ MCP_SERVER_PROXY_ENDPOINT:.*| MCP_SERVER_PROXY_ENDPOINT: $MCP_ENDPOINT|g" docker-compose.yml
fi
fi fi
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "已更新 MCP 访问地址为: $MCP_ENDPOINT" echo "已更新 MCP 访问地址为: $MCP_ENDPOINT"
else else
echo "警告: 替换 MCP 地址失败,请手动编辑 config.json 中的 mcpServerProxyEndpoint" echo "警告: 替换 MCP 地址失败,请手动编辑 docker-compose.yml 中的 MCP_SERVER_PROXY_ENDPOINT 或 config.json 中的 mcpServerProxyEndpoint"
fi fi
else else
echo "警告: 未设置 MCP 地址,请手动编辑 config.json 中的 mcpServerProxyEndpoint" echo "警告: 未设置 MCP 地址,请手动编辑 docker-compose.yml 中的 MCP_SERVER_PROXY_ENDPOINT 或 config.json 中的 mcpServerProxyEndpoint"
fi fi
if [ "$DEPLOY_VERSION" != "main" ]; then if [ "$DEPLOY_VERSION" != "main" ]; then
......
...@@ -17,6 +17,9 @@ const SYSTEM_STRING_LENGTH_UNIT = 1_000_000; ...@@ -17,6 +17,9 @@ const SYSTEM_STRING_LENGTH_UNIT = 1_000_000;
const LogLevelSchema = z.enum(['trace', 'debug', 'info', 'warning', 'error', 'fatal']); const LogLevelSchema = z.enum(['trace', 'debug', 'info', 'warning', 'error', 'fatal']);
const StorageVendorSchema = z.enum(['minio', 'aws-s3', 'cos', 'oss']); const StorageVendorSchema = z.enum(['minio', 'aws-s3', 'cos', 'oss']);
const StorageCosProtocolSchema = z.enum(['https:', 'http:']); const StorageCosProtocolSchema = z.enum(['https:', 'http:']);
const AgentSandboxProxyUrlSchema = z.string().refine((url) => /^wss?:\/\//.test(url), {
message: 'AGENT_SANDBOX_PROXY_URL must start with ws:// or wss://'
});
const TEST_INVOKE_TOKEN_SECRET = 'fastgpt_test_invoke_token_secret_32'; const TEST_INVOKE_TOKEN_SECRET = 'fastgpt_test_invoke_token_secret_32';
/** /**
...@@ -74,6 +77,7 @@ export const serviceEnv = createEnv({ ...@@ -74,6 +77,7 @@ export const serviceEnv = createEnv({
.string() .string()
.min(32, 'AGENT_SANDBOX_PROXY_SECRET must be at least 32 characters') .min(32, 'AGENT_SANDBOX_PROXY_SECRET must be at least 32 characters')
.optional(), .optional(),
AGENT_SANDBOX_PROXY_URL: AgentSandboxProxyUrlSchema.optional(),
// Agent sandbox // Agent sandbox
AGENT_SANDBOX_PROVIDER: z.enum(['sealosdevbox', 'opensandbox', 'e2b']).optional(), AGENT_SANDBOX_PROVIDER: z.enum(['sealosdevbox', 'opensandbox', 'e2b']).optional(),
IDE_AGENT_BIND_ADDR: z.string().default('0.0.0.0:1318'), IDE_AGENT_BIND_ADDR: z.string().default('0.0.0.0:1318'),
...@@ -117,6 +121,26 @@ export const serviceEnv = createEnv({ ...@@ -117,6 +121,26 @@ export const serviceEnv = createEnv({
AGENT_SANDBOX_NPM_REGISTRY: z.string().optional(), AGENT_SANDBOX_NPM_REGISTRY: z.string().optional(),
AGENT_SANDBOX_PYPI_INDEX_URL: z.string().optional(), AGENT_SANDBOX_PYPI_INDEX_URL: z.string().optional(),
// PDF 增强解析
CUSTOM_PDF_PARSE_URL: UrlSchema.optional().meta({
description: '自定义 PDF 解析服务地址'
}),
CUSTOM_PDF_PARSE_KEY: z.string().optional().meta({
description: '自定义 PDF 解析服务密钥'
}),
DOC2X_KEY: z.string().optional().meta({
description: 'Doc2x PDF 解析服务密钥'
}),
TEXTIN_APP_ID: z.string().optional().meta({
description: '合合信息 Textin 服务 App ID'
}),
TEXTIN_SECRET_CODE: z.string().optional().meta({
description: '合合信息 Textin 服务 Secret Code'
}),
CUSTOM_PDF_PARSE_PRICE: NumSchema.default(0).meta({
description: 'PDF 增强解析单价'
}),
// ==================== 数据库与缓存 ==================== // ==================== 数据库与缓存 ====================
// Redisg // Redisg
REDIS_URL: z.string().default('redis://default:mypassword@localhost:6379'), REDIS_URL: z.string().default('redis://default:mypassword@localhost:6379'),
...@@ -151,6 +175,12 @@ export const serviceEnv = createEnv({ ...@@ -151,6 +175,12 @@ export const serviceEnv = createEnv({
MILVUS_ADDRESS: z.string().optional().meta({ description: 'Milvus 向量库连接参数' }), MILVUS_ADDRESS: z.string().optional().meta({ description: 'Milvus 向量库连接参数' }),
MILVUS_TOKEN: z.string().optional().meta({ description: 'Milvus 向量库Token' }), MILVUS_TOKEN: z.string().optional().meta({ description: 'Milvus 向量库Token' }),
OPENGAUSS_URL: z.string().optional().meta({ description: 'openGauss 向量库连接参数' }), OPENGAUSS_URL: z.string().optional().meta({ description: 'openGauss 向量库连接参数' }),
HNSW_EF_SEARCH: IntSchema.min(1).default(100).meta({
description: '向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效'
}),
HNSW_MAX_SCAN_TUPLES: IntSchema.min(1).default(100000).meta({
description: '向量检索最大扫描数据量,仅对 PG 生效'
}),
// 对象存储 // 对象存储
STORAGE_VENDOR: StorageVendorSchema.default('minio'), STORAGE_VENDOR: StorageVendorSchema.default('minio'),
...@@ -223,6 +253,9 @@ export const serviceEnv = createEnv({ ...@@ -223,6 +253,9 @@ export const serviceEnv = createEnv({
.string() .string()
.optional() .optional()
.meta({ description: '自定义跨域;不配置时默认允许所有跨域(逗号分割)' }), .meta({ description: '自定义跨域;不配置时默认允许所有跨域(逗号分割)' }),
FILE_URL_WHITELIST: z.string().optional().meta({
description: '文件 URL 白名单,逗号或空白分隔'
}),
MULTIPLE_DATA_TO_BASE64: BoolSchema.default(true).meta({ MULTIPLE_DATA_TO_BASE64: BoolSchema.default(true).meta({
description: '是否强制将图片、音频、视频转成 base64 传递给模型' description: '是否强制将图片、音频、视频转成 base64 传递给模型'
}), }),
...@@ -287,6 +320,21 @@ export const serviceEnv = createEnv({ ...@@ -287,6 +320,21 @@ export const serviceEnv = createEnv({
EVAL_CONCURRENCY: IntSchema.default(3).meta({ EVAL_CONCURRENCY: IntSchema.default(3).meta({
description: '评估任务 worker 并发数' description: '评估任务 worker 并发数'
}), }),
DATASET_PARSE_MAX_PROCESS: IntSchema.min(1).default(10).meta({
description: '知识库文件解析最大并发数'
}),
VECTOR_MAX_PROCESS: IntSchema.min(1).default(10).meta({
description: '向量训练最大并发数'
}),
QA_MAX_PROCESS: IntSchema.min(1).default(10).meta({
description: '问答拆分最大并发数'
}),
VLM_MAX_PROCESS: IntSchema.min(1).default(10).meta({
description: '图片理解模型最大处理并发数'
}),
WORKFLOW_HTTP_IGNORE_HTTPS_CERT: BoolSchema.default(false).meta({
description: '工作流 HTTP 节点是否忽略 HTTPS 证书校验'
}),
// ==================== 资源限制 ==================== // ==================== 资源限制 ====================
SERVICE_REQUEST_MAX_CONTENT_LENGTH: IntSchema.default(10).meta({ SERVICE_REQUEST_MAX_CONTENT_LENGTH: IntSchema.default(10).meta({
description: '服务器接收请求的最大大小(MB)' description: '服务器接收请求的最大大小(MB)'
...@@ -336,6 +384,14 @@ if (serviceEnv.WORKFLOW_PARALLEL_MAX_CONCURRENCY > serviceEnv.WORKFLOW_MAX_LOOP_ ...@@ -336,6 +384,14 @@ if (serviceEnv.WORKFLOW_PARALLEL_MAX_CONCURRENCY > serviceEnv.WORKFLOW_MAX_LOOP_
); );
} }
if (!isPhaseProductionBuild && hasAgentSandboxConfigFromEnv(process.env)) {
if (!serviceEnv.AGENT_SANDBOX_PROXY_URL) {
throw new Error(
'AGENT_SANDBOX_PROXY_URL is required when Agent Sandbox is enabled. Please configure a browser-accessible ws:// or wss:// agent-sandbox-proxy URL.'
);
}
}
export const SYSTEM_MAX_STRING_LENGTH = export const SYSTEM_MAX_STRING_LENGTH =
serviceEnv.SYSTEM_MAX_STRING_LENGTH_M * SYSTEM_STRING_LENGTH_UNIT; serviceEnv.SYSTEM_MAX_STRING_LENGTH_M * SYSTEM_STRING_LENGTH_UNIT;
......
...@@ -13,9 +13,10 @@ const originalEnv = { ...@@ -13,9 +13,10 @@ const originalEnv = {
AGENT_SANDBOX_OPENSANDBOX_IMAGE_REPO: process.env.AGENT_SANDBOX_OPENSANDBOX_IMAGE_REPO, AGENT_SANDBOX_OPENSANDBOX_IMAGE_REPO: process.env.AGENT_SANDBOX_OPENSANDBOX_IMAGE_REPO,
AGENT_SANDBOX_OPENSANDBOX_IMAGE_TAG: process.env.AGENT_SANDBOX_OPENSANDBOX_IMAGE_TAG, AGENT_SANDBOX_OPENSANDBOX_IMAGE_TAG: process.env.AGENT_SANDBOX_OPENSANDBOX_IMAGE_TAG,
AGENT_SANDBOX_DISK_MB: process.env.AGENT_SANDBOX_DISK_MB, AGENT_SANDBOX_DISK_MB: process.env.AGENT_SANDBOX_DISK_MB,
AGENT_SANDBOX_PROXY_SECRET: process.env.AGENT_SANDBOX_PROXY_SECRET,
AGENT_SANDBOX_PROXY_URL: process.env.AGENT_SANDBOX_PROXY_URL
AGENT_SANDBOX_WS_MAX_MESSAGE_BYTES: process.env.AGENT_SANDBOX_WS_MAX_MESSAGE_BYTES, AGENT_SANDBOX_WS_MAX_MESSAGE_BYTES: process.env.AGENT_SANDBOX_WS_MAX_MESSAGE_BYTES,
AGENT_SANDBOX_WS_MAX_FRAME_BYTES: process.env.AGENT_SANDBOX_WS_MAX_FRAME_BYTES, AGENT_SANDBOX_WS_MAX_FRAME_BYTES: process.env.AGENT_SANDBOX_WS_MAX_FRAME_BYTES,
AGENT_SANDBOX_PROXY_SECRET: process.env.AGENT_SANDBOX_PROXY_SECRET
}; };
const loadSandboxConfigModule = async () => { const loadSandboxConfigModule = async () => {
...@@ -41,6 +42,7 @@ describe('sandbox provider config', () => { ...@@ -41,6 +42,7 @@ describe('sandbox provider config', () => {
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
vi.stubEnv('AGENT_SANDBOX_PROXY_SECRET', 'test-secret-123456789012345678901234'); vi.stubEnv('AGENT_SANDBOX_PROXY_SECRET', 'test-secret-123456789012345678901234');
vi.stubEnv('AGENT_SANDBOX_PROXY_URL', 'ws://localhost:1006');
}); });
afterEach(() => { afterEach(() => {
...@@ -71,6 +73,7 @@ describe('sandbox provider config', () => { ...@@ -71,6 +73,7 @@ describe('sandbox provider config', () => {
); );
vi.stubEnv('AGENT_SANDBOX_WS_MAX_FRAME_BYTES', originalEnv.AGENT_SANDBOX_WS_MAX_FRAME_BYTES); vi.stubEnv('AGENT_SANDBOX_WS_MAX_FRAME_BYTES', originalEnv.AGENT_SANDBOX_WS_MAX_FRAME_BYTES);
vi.stubEnv('AGENT_SANDBOX_PROXY_SECRET', originalEnv.AGENT_SANDBOX_PROXY_SECRET); vi.stubEnv('AGENT_SANDBOX_PROXY_SECRET', originalEnv.AGENT_SANDBOX_PROXY_SECRET);
vi.stubEnv('AGENT_SANDBOX_PROXY_URL', originalEnv.AGENT_SANDBOX_PROXY_URL);
vi.unstubAllGlobals(); vi.unstubAllGlobals();
}); });
......
...@@ -9,7 +9,11 @@ const originalEnv = { ...@@ -9,7 +9,11 @@ const originalEnv = {
AES256_SECRET_KEY: process.env.AES256_SECRET_KEY, AES256_SECRET_KEY: process.env.AES256_SECRET_KEY,
INVOKE_TOKEN_SECRET: process.env.INVOKE_TOKEN_SECRET, INVOKE_TOKEN_SECRET: process.env.INVOKE_TOKEN_SECRET,
VITEST: process.env.VITEST, VITEST: process.env.VITEST,
NODE_ENV: process.env.NODE_ENV NODE_ENV: process.env.NODE_ENV,
AGENT_SANDBOX_PROVIDER: process.env.AGENT_SANDBOX_PROVIDER,
AGENT_SANDBOX_OPENSANDBOX_BASEURL: process.env.AGENT_SANDBOX_OPENSANDBOX_BASEURL,
AGENT_SANDBOX_OPENSANDBOX_API_KEY: process.env.AGENT_SANDBOX_OPENSANDBOX_API_KEY,
AGENT_SANDBOX_PROXY_URL: process.env.AGENT_SANDBOX_PROXY_URL
}; };
const importServiceEnv = async () => { const importServiceEnv = async () => {
...@@ -27,6 +31,16 @@ describe('serviceEnv', () => { ...@@ -27,6 +31,16 @@ describe('serviceEnv', () => {
vi.stubEnv('INVOKE_TOKEN_SECRET', originalEnv.INVOKE_TOKEN_SECRET); vi.stubEnv('INVOKE_TOKEN_SECRET', originalEnv.INVOKE_TOKEN_SECRET);
vi.stubEnv('VITEST', originalEnv.VITEST); vi.stubEnv('VITEST', originalEnv.VITEST);
vi.stubEnv('NODE_ENV', originalEnv.NODE_ENV); vi.stubEnv('NODE_ENV', originalEnv.NODE_ENV);
vi.stubEnv('AGENT_SANDBOX_PROVIDER', originalEnv.AGENT_SANDBOX_PROVIDER);
vi.stubEnv(
'AGENT_SANDBOX_OPENSANDBOX_BASEURL',
originalEnv.AGENT_SANDBOX_OPENSANDBOX_BASEURL
);
vi.stubEnv(
'AGENT_SANDBOX_OPENSANDBOX_API_KEY',
originalEnv.AGENT_SANDBOX_OPENSANDBOX_API_KEY
);
vi.stubEnv('AGENT_SANDBOX_PROXY_URL', originalEnv.AGENT_SANDBOX_PROXY_URL);
}); });
it('validates SYSTEM_MAX_STRING_LENGTH_M during service env init', async () => { it('validates SYSTEM_MAX_STRING_LENGTH_M during service env init', async () => {
...@@ -112,4 +126,43 @@ describe('serviceEnv', () => { ...@@ -112,4 +126,43 @@ describe('serviceEnv', () => {
const customEnv = await importServiceEnv(); const customEnv = await importServiceEnv();
expect(customEnv.serviceEnv.AGENT_SANDBOX_DISK_MB).toBe(333); expect(customEnv.serviceEnv.AGENT_SANDBOX_DISK_MB).toBe(333);
}); });
it('未启用 Agent Sandbox 时允许 AGENT_SANDBOX_PROXY_URL 为空', async () => {
vi.stubEnv('FILE_TOKEN_KEY', 'filetokenkey');
vi.stubEnv('AES256_SECRET_KEY', 'fastgptsecret');
vi.stubEnv('INVOKE_TOKEN_SECRET', validInvokeTokenSecret);
vi.stubEnv('VITEST', 'true');
vi.stubEnv('AGENT_SANDBOX_PROVIDER', '');
vi.stubEnv('AGENT_SANDBOX_PROXY_URL', '');
await expect(importServiceEnv()).resolves.toBeDefined();
});
it('启用 opensandbox 时要求配置 AGENT_SANDBOX_PROXY_URL', async () => {
vi.stubEnv('FILE_TOKEN_KEY', 'filetokenkey');
vi.stubEnv('AES256_SECRET_KEY', 'fastgptsecret');
vi.stubEnv('INVOKE_TOKEN_SECRET', validInvokeTokenSecret);
vi.stubEnv('VITEST', 'true');
vi.stubEnv('NODE_ENV', 'development');
vi.stubEnv('AGENT_SANDBOX_PROVIDER', 'opensandbox');
vi.stubEnv('AGENT_SANDBOX_OPENSANDBOX_BASEURL', 'http://mock-opensandbox.local');
vi.stubEnv('AGENT_SANDBOX_OPENSANDBOX_API_KEY', 'mock-opensandbox-api-key');
vi.stubEnv('AGENT_SANDBOX_PROXY_URL', '');
await expect(importServiceEnv()).rejects.toThrow('AGENT_SANDBOX_PROXY_URL is required');
});
it('启用 opensandbox 时要求 AGENT_SANDBOX_PROXY_URL 是 WebSocket 地址', async () => {
vi.stubEnv('FILE_TOKEN_KEY', 'filetokenkey');
vi.stubEnv('AES256_SECRET_KEY', 'fastgptsecret');
vi.stubEnv('INVOKE_TOKEN_SECRET', validInvokeTokenSecret);
vi.stubEnv('VITEST', 'true');
vi.stubEnv('NODE_ENV', 'development');
vi.stubEnv('AGENT_SANDBOX_PROVIDER', 'opensandbox');
vi.stubEnv('AGENT_SANDBOX_OPENSANDBOX_BASEURL', 'http://mock-opensandbox.local');
vi.stubEnv('AGENT_SANDBOX_OPENSANDBOX_API_KEY', 'mock-opensandbox-api-key');
vi.stubEnv('AGENT_SANDBOX_PROXY_URL', 'http://localhost:1006');
await expect(importServiceEnv()).rejects.toThrow('AGENT_SANDBOX_PROXY_URL');
});
}); });
...@@ -35,6 +35,9 @@ CODE_SANDBOX_TOKEN=codesandbox ...@@ -35,6 +35,9 @@ CODE_SANDBOX_TOKEN=codesandbox
AIPROXY_API_ENDPOINT=http://localhost:3010 AIPROXY_API_ENDPOINT=http://localhost:3010
AIPROXY_API_TOKEN=token AIPROXY_API_TOKEN=token
# MCP Server 代理地址,用于 MCP 使用方式页拼接 SSE 地址(末尾不要带 /)
MCP_SERVER_PROXY_ENDPOINT=http://localhost:3003
# 插件市场地址 # 插件市场地址
MARKETPLACE_URL=https://v2.marketplace.fastgpt.cn MARKETPLACE_URL=https://v2.marketplace.fastgpt.cn
...@@ -69,6 +72,20 @@ AGENT_SANDBOX_NPM_REGISTRY= ...@@ -69,6 +72,20 @@ AGENT_SANDBOX_NPM_REGISTRY=
# Agent 沙箱内 pip/python -m pip/uv 使用的 PyPI index URL(可选) # Agent 沙箱内 pip/python -m pip/uv 使用的 PyPI index URL(可选)
AGENT_SANDBOX_PYPI_INDEX_URL= AGENT_SANDBOX_PYPI_INDEX_URL=
# ==================== PDF 增强解析(可选) ====================
# 自定义 PDF 解析服务地址
# CUSTOM_PDF_PARSE_URL=
# 自定义 PDF 解析服务密钥
# CUSTOM_PDF_PARSE_KEY=
# Doc2x PDF 解析服务密钥
# DOC2X_KEY=
# 合合信息 Textin 服务 App ID
# TEXTIN_APP_ID=
# 合合信息 Textin 服务 Secret Code
# TEXTIN_SECRET_CODE=
# PDF 增强解析单价
CUSTOM_PDF_PARSE_PRICE=0
# ==================== 沙盒代理 (agent-sandbox-proxy) 与网络配置 ==================== # ==================== 沙盒代理 (agent-sandbox-proxy) 与网络配置 ====================
# JWT 验签与内网安全物理阻断密钥 (必须与 Rust Proxy 的 AGENT_SANDBOX_PROXY_SECRET 环境变量保持完全一致) # JWT 验签与内网安全物理阻断密钥 (必须与 Rust Proxy 的 AGENT_SANDBOX_PROXY_SECRET 环境变量保持完全一致)
# 生产环境必须配置为至少 32 字节的高强度随机值,不能使用示例占位。 # 生产环境必须配置为至少 32 字节的高强度随机值,不能使用示例占位。
...@@ -123,6 +140,10 @@ PG_URL=postgresql://username:password@localhost:5432/postgres ...@@ -123,6 +140,10 @@ PG_URL=postgresql://username:password@localhost:5432/postgres
# MILVUS_TOKEN= # MILVUS_TOKEN=
# openGauss 向量库连接参数 # openGauss 向量库连接参数
# OPENGAUSS_URL=postgresql://gaussdb:FastGPT@123@localhost:5432/fastgpt # OPENGAUSS_URL=postgresql://gaussdb:FastGPT@123@localhost:5432/fastgpt
# 向量检索 hnsw ef_search 参数,仅对 PG / OB / OpenGauss 生效
HNSW_EF_SEARCH=100
# 向量检索最大扫描数据量,仅对 PG 生效
HNSW_MAX_SCAN_TUPLES=100000
# ==================== 日志配置 ==================== # ==================== 日志配置 ====================
# 日志等级: trace | debug | info | warning | error | fatal # 日志等级: trace | debug | info | warning | error | fatal
...@@ -168,6 +189,8 @@ PASSWORD_EXPIRED_MONTH= ...@@ -168,6 +189,8 @@ PASSWORD_EXPIRED_MONTH=
MAX_LOGIN_SESSION= MAX_LOGIN_SESSION=
# 自定义跨域;不配置时默认允许所有跨域(逗号分割) # 自定义跨域;不配置时默认允许所有跨域(逗号分割)
ALLOWED_ORIGINS= ALLOWED_ORIGINS=
# 文件 URL 白名单,逗号或空白分隔
# FILE_URL_WHITELIST=
# 强制将图片转成 base64 传递给模型 # 强制将图片转成 base64 传递给模型
MULTIPLE_DATA_TO_BASE64=true MULTIPLE_DATA_TO_BASE64=true
...@@ -176,8 +199,6 @@ MULTIPLE_DATA_TO_BASE64=true ...@@ -176,8 +199,6 @@ MULTIPLE_DATA_TO_BASE64=true
SHOW_COUPON=false SHOW_COUPON=false
# 是否展示优惠券功能 # 是否展示优惠券功能
SHOW_DISCOUNT_COUPON=false SHOW_DISCOUNT_COUPON=false
# 自定义 config.json 路径
CONFIG_JSON_PATH=
# 申请应用备案地址 # 申请应用备案地址
APP_REGISTRATION_URL= APP_REGISTRATION_URL=
# 是否隐藏版权信息配置,只有值为 true 时隐藏 # 是否隐藏版权信息配置,只有值为 true 时隐藏
...@@ -206,18 +227,28 @@ SKIP_FILE_TYPE_CHECK=false ...@@ -206,18 +227,28 @@ SKIP_FILE_TYPE_CHECK=false
WECHAT_CHANNEL_CONCURRENCY=1000 WECHAT_CHANNEL_CONCURRENCY=1000
# 文件解析 worker 并发数 # 文件解析 worker 并发数
PARSE_FILE_WORKERS=10 PARSE_FILE_WORKERS=10
# 知识库文件解析队列最大并发数
DATASET_PARSE_MAX_PROCESS=10
# 文件解析超时时间(秒) # 文件解析超时时间(秒)
PARSE_FILE_TIMEOUT_SECONDS=600 PARSE_FILE_TIMEOUT_SECONDS=600
# HTML 转 Markdown worker 并发数 # HTML 转 Markdown worker 并发数
HTML_TO_MARKDOWN_WORKERS=10 HTML_TO_MARKDOWN_WORKERS=10
# 文本切块 worker 并发数 # 文本切块 worker 并发数
TEXT_TO_CHUNKS_WORKERS=10 TEXT_TO_CHUNKS_WORKERS=10
# 向量训练队列最大并发数
VECTOR_MAX_PROCESS=10
# 问答拆分队列最大并发数
QA_MAX_PROCESS=10
# 图片理解模型处理队列最大并发数
VLM_MAX_PROCESS=10
# 工作流最大运行次数,避免极端死循环 # 工作流最大运行次数,避免极端死循环
WORKFLOW_MAX_RUN_TIMES=500 WORKFLOW_MAX_RUN_TIMES=500
# 循环/并行节点最大输入数组长度(默认 100) # 循环/并行节点最大输入数组长度(默认 100)
WORKFLOW_MAX_LOOP_TIMES=100 WORKFLOW_MAX_LOOP_TIMES=100
# 并行节点并发上限(最终会 clamp 到 [5, 100],默认 10) # 并行节点并发上限(最终会 clamp 到 [5, 100],默认 10)
WORKFLOW_PARALLEL_MAX_CONCURRENCY=10 WORKFLOW_PARALLEL_MAX_CONCURRENCY=10
# 工作流 HTTP 节点是否忽略 HTTPS 证书校验
WORKFLOW_HTTP_IGNORE_HTTPS_CERT=false
# 工作流 QPM(若用户套餐有限制,这里不生效) # 工作流 QPM(若用户套餐有限制,这里不生效)
CHAT_MAX_QPM=5000 CHAT_MAX_QPM=5000
......
...@@ -91,7 +91,6 @@ COPY --from=maindeps /app/node_modules/@zilliz/milvus2-sdk-node ./node_modules/@ ...@@ -91,7 +91,6 @@ COPY --from=maindeps /app/node_modules/@zilliz/milvus2-sdk-node ./node_modules/@
# copy package.json to version file # copy package.json to version file
COPY --from=builder /app/projects/app/package.json ./package.json COPY --from=builder /app/projects/app/package.json ./package.json
# copy config and data files (use --chown to avoid extra layer from chown) # copy config and data files (use --chown to avoid extra layer from chown)
COPY --chown=nextjs:nodejs ./projects/app/data/config.json /app/data/config.json
COPY --chown=nextjs:nodejs ./projects/app/data/test.mp3 /app/data/test.mp3 COPY --chown=nextjs:nodejs ./projects/app/data/test.mp3 /app/data/test.mp3
COPY --chown=nextjs:nodejs ./projects/app/data/GeoLite2-City.mmdb /app/data/GeoLite2-City.mmdb COPY --chown=nextjs:nodejs ./projects/app/data/GeoLite2-City.mmdb /app/data/GeoLite2-City.mmdb
......
// 已使用 json5 进行解析,会自动去掉注释,无需手动去除
{
"feConfigs": {
"mcpServerProxyEndpoint": "http://localhost:3003" // mcp server 代理地址,例如: http://localhost:3004
},
"systemEnv": {
"datasetParseMaxProcess": 10, // 知识库文件解析最大线程数量
"vectorMaxProcess": 10, // 向量处理线程数量
"qaMaxProcess": 10, // 问答拆分线程数量
"vlmMaxProcess": 10, // 图片理解模型最大处理进程
"hnswEfSearch": 100, // 向量搜索参数,仅对 PG OB 生效。越大,搜索越精确,但是速度越慢。设置为100,有99%+精度。
"hnswMaxScanTuples": 100000, // 向量搜索最大扫描数据量,仅对 PG生效。
"customPdfParse": {
"url": "", // 自定义 PDF 解析服务地址
"key": "", // 自定义 PDF 解析服务密钥
"doc2xKey": "", // doc2x 服务密钥
"textinAppId": "", // 合合信息 Textin 服务 App ID
"textinSecretCode": "", // 合合信息 Textin 服务 Secret Code
"price": 0 // PDF 解析服务价格
}
}
}
import { createEnv } from '@t3-oss/env-core'; import { createEnv } from '@t3-oss/env-core';
import z from 'zod'; import z from 'zod';
import { isPhaseProductionBuild } from '@fastgpt/global/common/system/constants';
import { BoolSchema, IntSchema, UrlSchema } from '@fastgpt/global/common/zod'; import { BoolSchema, IntSchema, UrlSchema } from '@fastgpt/global/common/zod';
import { hasAgentSandboxConfig } from '@fastgpt/global/core/ai/sandbox/env';
const AgentSandboxProxyUrlSchema = z.string().refine((url) => /^wss?:\/\//.test(url), {
message: 'AGENT_SANDBOX_PROXY_URL must start with ws:// or wss://'
});
export const appEnv = createEnv({ export const appEnv = createEnv({
server: { server: {
DEFAULT_ROOT_PSW: z.string().default('123456'), DEFAULT_ROOT_PSW: z.string().default('123456'),
CONFIG_JSON_PATH: z.string().optional(), MCP_SERVER_PROXY_ENDPOINT: UrlSchema.optional(),
SYSTEM_NAME: z.string().default('AI'), SYSTEM_NAME: z.string().default('AI'),
SYSTEM_DESCRIPTION: z.string().default(''), SYSTEM_DESCRIPTION: z.string().default(''),
SYSTEM_FAVICON: z.string().default(''), SYSTEM_FAVICON: z.string().default(''),
...@@ -22,10 +16,8 @@ export const appEnv = createEnv({ ...@@ -22,10 +16,8 @@ export const appEnv = createEnv({
SHOW_DISCOUNT_COUPON: BoolSchema.default(false), SHOW_DISCOUNT_COUPON: BoolSchema.default(false),
HIDE_CHAT_COPYRIGHT_SETTING: BoolSchema.default(false), HIDE_CHAT_COPYRIGHT_SETTING: BoolSchema.default(false),
AGENT_SANDBOX_FREE_TIP: BoolSchema.default(false), AGENT_SANDBOX_FREE_TIP: BoolSchema.default(false),
AGENT_SANDBOX_PROXY_URL: AgentSandboxProxyUrlSchema.optional(),
OPENAPI_KEY_MAX_COUNT: IntSchema.min(1).default(100), OPENAPI_KEY_MAX_COUNT: IntSchema.min(1).default(100),
// 临时
MARKETPLACE_URL: UrlSchema.default('https://v2.marketplace.fastgpt.cn'), MARKETPLACE_URL: UrlSchema.default('https://v2.marketplace.fastgpt.cn'),
PASSWORD_EXPIRED_MONTH: IntSchema.optional() PASSWORD_EXPIRED_MONTH: IntSchema.optional()
}, },
...@@ -41,11 +33,3 @@ export const appEnv = createEnv({ ...@@ -41,11 +33,3 @@ export const appEnv = createEnv({
throw new Error(`Invalid app environment variables:\n${details}\n`); throw new Error(`Invalid app environment variables:\n${details}\n`);
} }
}); });
if (!isPhaseProductionBuild && hasAgentSandboxConfig(process.env)) {
if (!appEnv.AGENT_SANDBOX_PROXY_URL) {
throw new Error(
'AGENT_SANDBOX_PROXY_URL is required when Agent Sandbox is enabled. Please configure a browser-accessible ws:// or wss:// agent-sandbox-proxy URL.'
);
}
}
import fs, { existsSync } from 'fs'; import fs from 'fs';
import type { FastGPTFeConfigsType } from '@fastgpt/global/common/system/types/index'; import type { FastGPTFeConfigsType } from '@fastgpt/global/common/system/types/index';
import type { FastGPTConfigFileType } from '@fastgpt/global/common/system/types/index'; import type { FastGPTConfigFileType } from '@fastgpt/global/common/system/types/index';
import { getFastGPTConfigFromDB } from '@fastgpt/service/common/system/config/controller'; import { getFastGPTConfigFromDB } from '@fastgpt/service/common/system/config/controller';
import { isProduction } from '@fastgpt/global/common/system/constants';
import { initFastGPTConfig } from '@fastgpt/service/common/system/tools'; import { initFastGPTConfig } from '@fastgpt/service/common/system/tools';
import json5 from 'json5'; import json5 from 'json5';
import { defaultTemplateTypes } from '@fastgpt/web/core/workflow/constants'; import { defaultTemplateTypes } from '@fastgpt/web/core/workflow/constants';
...@@ -37,29 +36,6 @@ const pluginFeaturesProbeTimeoutMs = 3000; ...@@ -37,29 +36,6 @@ const pluginFeaturesProbeTimeoutMs = 3000;
const defaultOpenSourceLoginGuideDocUrl = const defaultOpenSourceLoginGuideDocUrl =
'https://doc.fastgpt.io/zh-CN/guide/version/cloud/faq#%E8%B4%A6%E5%8F%B7%E7%99%BB%E5%BD%95%E9%97%AE%E9%A2%98'; 'https://doc.fastgpt.io/zh-CN/guide/version/cloud/faq#%E8%B4%A6%E5%8F%B7%E7%99%BB%E5%BD%95%E9%97%AE%E9%A2%98';
export const readConfigData = async (name: string) => {
const splitName = name.split('.');
const devName = `${splitName[0]}.local.${splitName[1]}`;
const filename = (() => {
if (!isProduction) {
// check local file exists
const hasLocalFile = existsSync(`data/${devName}`);
if (hasLocalFile) {
return `data/${devName}`;
}
return `data/${name}`;
}
// Fallback to default production path
const envPath = appEnv.CONFIG_JSON_PATH || '/app/data';
return `${envPath}/${name}`;
})();
const content = await fs.promises.readFile(filename, 'utf-8');
return content;
};
/* Init global variables */ /* Init global variables */
export function initGlobalVariables() { export function initGlobalVariables() {
function initPlusRequest() { function initPlusRequest() {
...@@ -161,24 +137,18 @@ async function getPluginRemoteDebugEnabled() { ...@@ -161,24 +137,18 @@ async function getPluginRemoteDebugEnabled() {
} }
export async function initSystemConfig() { export async function initSystemConfig() {
// load config const [{ fastgptConfig, licenseData }, pluginRemoteDebug] = await Promise.all([
const [{ fastgptConfig, licenseData }, fileConfig, pluginRemoteDebug] = await Promise.all([
getFastGPTConfigFromDB(), getFastGPTConfigFromDB(),
readConfigData('config.json'),
getPluginRemoteDebugEnabled() getPluginRemoteDebugEnabled()
]); ]);
global.licenseData = licenseData; global.licenseData = licenseData;
const fileRes = json5.parse(fileConfig) as FastGPTConfigFileType;
// get config from database
const config: FastGPTConfigFileType = { const config: FastGPTConfigFileType = {
feConfigs: { feConfigs: {
...fileRes?.feConfigs,
...defaultFeConfigs, ...defaultFeConfigs,
mcpServerProxyEndpoint: appEnv.MCP_SERVER_PROXY_ENDPOINT,
...(fastgptConfig.feConfigs || {}), ...(fastgptConfig.feConfigs || {}),
limit: { limit: {
...fileRes?.feConfigs?.limit,
...defaultFeConfigs.limit, ...defaultFeConfigs.limit,
...(fastgptConfig.feConfigs?.limit || {}) ...(fastgptConfig.feConfigs?.limit || {})
}, },
...@@ -193,12 +163,35 @@ export async function initSystemConfig() { ...@@ -193,12 +163,35 @@ export async function initSystemConfig() {
payFormUrl: appEnv.PAY_FORM_URL || '', payFormUrl: appEnv.PAY_FORM_URL || '',
agentSandboxFree: appEnv.AGENT_SANDBOX_FREE_TIP, agentSandboxFree: appEnv.AGENT_SANDBOX_FREE_TIP,
agentSandboxProxyUrl: appEnv.AGENT_SANDBOX_PROXY_URL || '' agentSandboxProxyUrl: serviceEnv.AGENT_SANDBOX_PROXY_URL || ''
},
systemEnv: {
...fileRes.systemEnv,
...(fastgptConfig.systemEnv || {})
}, },
systemEnv: Object.assign(
{
datasetParseMaxProcess: serviceEnv.DATASET_PARSE_MAX_PROCESS,
vectorMaxProcess: serviceEnv.VECTOR_MAX_PROCESS,
qaMaxProcess: serviceEnv.QA_MAX_PROCESS,
vlmMaxProcess: serviceEnv.VLM_MAX_PROCESS,
hnswEfSearch: serviceEnv.HNSW_EF_SEARCH,
hnswMaxScanTuples: serviceEnv.HNSW_MAX_SCAN_TUPLES,
customPdfParse: {
url: serviceEnv.CUSTOM_PDF_PARSE_URL,
key: serviceEnv.CUSTOM_PDF_PARSE_KEY,
doc2xKey: serviceEnv.DOC2X_KEY,
textinAppId: serviceEnv.TEXTIN_APP_ID,
textinSecretCode: serviceEnv.TEXTIN_SECRET_CODE,
price: serviceEnv.CUSTOM_PDF_PARSE_PRICE
},
fileUrlWhitelist: serviceEnv.FILE_URL_WHITELIST
? serviceEnv.FILE_URL_WHITELIST.split(/[,;\s]+/)
.map((item) => item.trim())
.filter(Boolean)
: undefined,
workflowHttpNode: {
ignoreHttpsCertificate: serviceEnv.WORKFLOW_HTTP_IGNORE_HTTPS_CERT
}
},
fastgptConfig.systemEnv || {}
),
subPlans: fastgptConfig.subPlans subPlans: fastgptConfig.subPlans
}; };
......
...@@ -5,31 +5,13 @@ const importAppEnv = async () => { ...@@ -5,31 +5,13 @@ const importAppEnv = async () => {
return import('../src/env'); return import('../src/env');
}; };
const disableAgentSandboxEnv = () => {
vi.stubEnv('AGENT_SANDBOX_PROVIDER', '');
vi.stubEnv('AGENT_SANDBOX_OPENSANDBOX_BASEURL', '');
vi.stubEnv('AGENT_SANDBOX_OPENSANDBOX_API_KEY', '');
vi.stubEnv('AGENT_SANDBOX_SEALOS_BASEURL', '');
vi.stubEnv('AGENT_SANDBOX_SEALOS_TOKEN', '');
vi.stubEnv('AGENT_SANDBOX_E2B_API_KEY', '');
vi.stubEnv('AGENT_SANDBOX_PROXY_URL', '');
};
describe('app env validation', () => { describe('app env validation', () => {
afterEach(() => { afterEach(() => {
vi.unstubAllEnvs(); vi.unstubAllEnvs();
vi.resetModules(); vi.resetModules();
}); });
it('未启用 Agent Sandbox 时允许 AGENT_SANDBOX_PROXY_URL 为空', async () => {
vi.stubEnv('AGENT_SANDBOX_PROVIDER', '');
vi.stubEnv('AGENT_SANDBOX_PROXY_URL', '');
await expect(importAppEnv()).resolves.toBeDefined();
});
it('OPENAPI_KEY_MAX_COUNT 默认值为 100,且允许配置为最小值 1', async () => { it('OPENAPI_KEY_MAX_COUNT 默认值为 100,且允许配置为最小值 1', async () => {
disableAgentSandboxEnv();
vi.stubEnv('OPENAPI_KEY_MAX_COUNT', ''); vi.stubEnv('OPENAPI_KEY_MAX_COUNT', '');
await expect(importAppEnv()).resolves.toMatchObject({ await expect(importAppEnv()).resolves.toMatchObject({
...@@ -48,7 +30,6 @@ describe('app env validation', () => { ...@@ -48,7 +30,6 @@ describe('app env validation', () => {
}); });
it('OPENAPI_KEY_MAX_COUNT 必须是大于等于 1 的整数', async () => { it('OPENAPI_KEY_MAX_COUNT 必须是大于等于 1 的整数', async () => {
disableAgentSandboxEnv();
vi.stubEnv('OPENAPI_KEY_MAX_COUNT', '0'); vi.stubEnv('OPENAPI_KEY_MAX_COUNT', '0');
await expect(importAppEnv()).rejects.toThrow('OPENAPI_KEY_MAX_COUNT'); await expect(importAppEnv()).rejects.toThrow('OPENAPI_KEY_MAX_COUNT');
...@@ -57,22 +38,4 @@ describe('app env validation', () => { ...@@ -57,22 +38,4 @@ describe('app env validation', () => {
await expect(importAppEnv()).rejects.toThrow('OPENAPI_KEY_MAX_COUNT'); await expect(importAppEnv()).rejects.toThrow('OPENAPI_KEY_MAX_COUNT');
}); });
it('启用 opensandbox 时要求配置 AGENT_SANDBOX_PROXY_URL', async () => {
vi.stubEnv('AGENT_SANDBOX_PROVIDER', 'opensandbox');
vi.stubEnv('AGENT_SANDBOX_OPENSANDBOX_BASEURL', 'http://mock-opensandbox.local');
vi.stubEnv('AGENT_SANDBOX_OPENSANDBOX_API_KEY', 'mock-opensandbox-api-key');
vi.stubEnv('AGENT_SANDBOX_PROXY_URL', '');
await expect(importAppEnv()).rejects.toThrow('AGENT_SANDBOX_PROXY_URL is required');
});
it('启用 opensandbox 时要求 AGENT_SANDBOX_PROXY_URL 是 WebSocket 地址', async () => {
vi.stubEnv('AGENT_SANDBOX_PROVIDER', 'opensandbox');
vi.stubEnv('AGENT_SANDBOX_OPENSANDBOX_BASEURL', 'http://mock-opensandbox.local');
vi.stubEnv('AGENT_SANDBOX_OPENSANDBOX_API_KEY', 'mock-opensandbox-api-key');
vi.stubEnv('AGENT_SANDBOX_PROXY_URL', 'http://localhost:1006');
await expect(importAppEnv()).rejects.toThrow('AGENT_SANDBOX_PROXY_URL');
});
}); });
...@@ -11,9 +11,6 @@ vi.mock(import('@/service/common/system'), async (importOriginal) => { ...@@ -11,9 +11,6 @@ vi.mock(import('@/service/common/system'), async (importOriginal) => {
getSystemVersion: async () => { getSystemVersion: async () => {
return '0.0.0'; return '0.0.0';
}, },
readConfigData: async () => {
return readFileSync('projects/app/data/config.json', 'utf-8');
},
initSystemConfig: async () => { initSystemConfig: async () => {
// read env from projects/app/.env // read env from projects/app/.env
const str = readFileSync('projects/app/.env.local', 'utf-8'); const str = readFileSync('projects/app/.env.local', 'utf-8');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment