Merge branch 'gzy' into 'master'
Gzy See merge request knowledge-base-bj/deerflow-server!114
This commit is contained in:
commit
da56a53a9c
6 files changed
+116
-50
No files matched your search
@@ -7,6 +7,7 @@ import { QueryClientProvider } from "@/components/query-client-provider";
|
||||
import { AuthSyncWatcher } from "@/core/auth/sync";
|
||||
import { I18nProvider } from "@/core/i18n/context";
|
||||
import { detectLocale } from "@/core/i18n/locale";
|
||||
import { resolveForcedThemeForPath } from "@/core/page-layout/chats-iframe-route";
|
||||
import { ChatProvider } from "@/contexts/ChatContext";
|
||||
import { ThemeProvider } from "@/contexts/ThemeContext";
|
||||
|
||||
@@ -29,7 +30,7 @@ import { NotFoundPage } from "./pages/NotFoundPage";
|
||||
function AppProviders({ children }: { children: React.ReactNode }) {
|
||||
const locale = useMemo(() => detectLocale(), []);
|
||||
const location = useLocation();
|
||||
const forcedTheme = location.pathname === "/landing" ? "light" : undefined;
|
||||
const forcedTheme = resolveForcedThemeForPath(location.pathname);
|
||||
|
||||
return (
|
||||
<NextThemesProvider
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
isChatsIframeWorkspacePath,
|
||||
resolveForcedThemeForPath,
|
||||
} from "./chats-iframe-route.ts";
|
||||
|
||||
test("matches only workspace chats_iframe routes", () => {
|
||||
assert.equal(
|
||||
isChatsIframeWorkspacePath("/page/workspace/chats_iframe/new"),
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
isChatsIframeWorkspacePath("/page/workspace/chats_iframe/thread-123"),
|
||||
true,
|
||||
);
|
||||
assert.equal(isChatsIframeWorkspacePath("/page/workspace/chats/new"), false);
|
||||
assert.equal(isChatsIframeWorkspacePath("/landing"), false);
|
||||
});
|
||||
|
||||
test("forces light theme for landing and chats_iframe routes only", () => {
|
||||
assert.equal(resolveForcedThemeForPath("/landing"), "light");
|
||||
assert.equal(
|
||||
resolveForcedThemeForPath("/page/workspace/chats_iframe/new"),
|
||||
"light",
|
||||
);
|
||||
assert.equal(
|
||||
resolveForcedThemeForPath("/page/workspace/chats_iframe/thread-123"),
|
||||
"light",
|
||||
);
|
||||
assert.equal(resolveForcedThemeForPath("/page/workspace/chats/new"), undefined);
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
export function isChatsIframeWorkspacePath(pathname: string): boolean {
|
||||
return (
|
||||
pathname === "/page/workspace/chats_iframe/new" ||
|
||||
pathname.startsWith("/page/workspace/chats_iframe/")
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveForcedThemeForPath(
|
||||
pathname: string,
|
||||
): "light" | undefined {
|
||||
if (pathname === "/landing" || isChatsIframeWorkspacePath(pathname)) {
|
||||
return "light";
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
@@ -3,8 +3,10 @@ import { Navigate, Route, Routes } from "react-router-dom";
|
||||
|
||||
import { PageSidebar } from "@/components/page-sidebar";
|
||||
import { PageSidebarDark } from "@/components/page-sidebar-dark";
|
||||
import { isChatsIframeWorkspacePath } from "@/core/page-layout/chats-iframe-route";
|
||||
import { readSidebarEnabled } from "@/core/page-layout/sidebar-enabled";
|
||||
import { useTheme } from "@/contexts/ThemeContext";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
import WorkspaceRoutes from "./WorkspaceRoutes";
|
||||
import StrategyRoutes from "./StrategyRoutes";
|
||||
@@ -16,17 +18,20 @@ import NotebookRoutes from "./NotebookRoutes";
|
||||
function PageLayout() {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const sidebarEnabled = useMemo(() => readSidebarEnabled(), []);
|
||||
const location = useLocation();
|
||||
const { theme } = useTheme();
|
||||
const isDark = theme === "dark";
|
||||
const pageSidebarAllowed =
|
||||
sidebarEnabled && !isChatsIframeWorkspacePath(location.pathname);
|
||||
|
||||
// h-full(100%)而非 h-screen(100vh):配合 globals.css 的 html/body/#root height:100%
|
||||
// 高度链,根布局跟随容器高度。全屏下 100% 解析到视口,与 h-screen 等价;无界等嵌套
|
||||
// 下容器不占满整屏时,高度才能正确收缩而非锁死整屏。
|
||||
return (
|
||||
<div className="h-full flex flex-col bg-muted/20">
|
||||
{sidebarEnabled && <Header collapsed={collapsed} />}
|
||||
{pageSidebarAllowed && <Header collapsed={collapsed} />}
|
||||
<div className="flex flex-1 overflow-hidden">
|
||||
{sidebarEnabled && (
|
||||
{pageSidebarAllowed && (
|
||||
isDark ? (
|
||||
<PageSidebarDark
|
||||
collapsed={collapsed}
|
||||
@@ -41,7 +46,7 @@ function PageLayout() {
|
||||
)}
|
||||
<main
|
||||
className={`flex-1 overflow-hidden ${
|
||||
!sidebarEnabled
|
||||
!pageSidebarAllowed
|
||||
? ""
|
||||
: isDark
|
||||
// 深色 sidebar:展开 118px(10 + 98 + 10 gap),收起 = 0 sidebar 完全消失,
|
||||
@@ -59,9 +64,9 @@ function PageLayout() {
|
||||
element={
|
||||
<WorkspaceRoutes
|
||||
pageSidebarCollapsed={collapsed}
|
||||
pageSidebarHidden={!sidebarEnabled}
|
||||
headerHidden={!sidebarEnabled}
|
||||
compactWorkspaceSidebar={sidebarEnabled}
|
||||
pageSidebarHidden={!pageSidebarAllowed}
|
||||
headerHidden={!pageSidebarAllowed}
|
||||
compactWorkspaceSidebar={pageSidebarAllowed}
|
||||
pageSidebarDark={isDark}
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ export function WorkspaceLayout({
|
||||
children,
|
||||
pageSidebarCollapsed,
|
||||
pageSidebarHidden = false,
|
||||
workspaceSidebarHidden = false,
|
||||
headerHidden = false,
|
||||
compactWorkspaceSidebar = false,
|
||||
wrapperOverflowHidden = false,
|
||||
@@ -76,6 +77,7 @@ export function WorkspaceLayout({
|
||||
children: ReactNode;
|
||||
pageSidebarCollapsed: boolean;
|
||||
pageSidebarHidden?: boolean;
|
||||
workspaceSidebarHidden?: boolean;
|
||||
headerHidden?: boolean;
|
||||
compactWorkspaceSidebar?: boolean;
|
||||
wrapperOverflowHidden?: boolean;
|
||||
@@ -109,7 +111,9 @@ export function WorkspaceLayout({
|
||||
data-page-sidebar-collapsed={pageSidebarCollapsed}
|
||||
defaultOpen
|
||||
>
|
||||
<WorkspaceSidebar compactChrome={compactWorkspaceSidebar} />
|
||||
{!workspaceSidebarHidden && (
|
||||
<WorkspaceSidebar compactChrome={compactWorkspaceSidebar} />
|
||||
)}
|
||||
<SidebarInset
|
||||
className={cn('min-w-0', insetOverflowHidden && 'overflow-hidden')}
|
||||
>
|
||||
@@ -205,7 +209,11 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="chats_iframe/new"
|
||||
element={
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<WorkspaceLayout
|
||||
{...layoutProps}
|
||||
pageSidebarHidden
|
||||
workspaceSidebarHidden
|
||||
>
|
||||
<ChatRuntime>
|
||||
<IframeChatPage />
|
||||
</ChatRuntime>
|
||||
@@ -217,6 +225,8 @@ export default function WorkspaceRoutes({
|
||||
element={
|
||||
<WorkspaceLayout
|
||||
{...layoutProps}
|
||||
pageSidebarHidden
|
||||
workspaceSidebarHidden
|
||||
wrapperOverflowHidden
|
||||
insetOverflowHidden
|
||||
>
|
||||
|
||||
@@ -36,7 +36,6 @@ models:
|
||||
# supports_vision: true
|
||||
# supports_thinking: true
|
||||
|
||||
|
||||
# - name: deepseek-v4-flash
|
||||
# display_name: DeepSeek V4 Flash
|
||||
# use: langchain_openai:ChatOpenAI
|
||||
@@ -118,7 +117,7 @@ models:
|
||||
display_name: deepseek-ai/DeepSeek-V4-Flash
|
||||
use: langchain_openai:ChatOpenAI
|
||||
model: deepseek-ai/DeepSeek-V4-Flash
|
||||
api_key: sk-ighylafootabtuthwueirmoycccyqtdgbifyhozduvolkdyt
|
||||
api_key: sk-ighylafootabtuthwueirmoycccyqtdgbifyhozduvolkdyt
|
||||
base_url: https://api.siliconflow.cn/v1/
|
||||
max_tokens: 4096
|
||||
temperature: 1.0
|
||||
@@ -128,7 +127,7 @@ models:
|
||||
display_name: Pro/MiniMaxAI/MiniMax-M2.5
|
||||
use: langchain_openai:ChatOpenAI
|
||||
model: Pro/MiniMaxAI/MiniMax-M2.5
|
||||
api_key: sk-ighylafootabtuthwueirmoycccyqtdgbifyhozduvolkdyt
|
||||
api_key: sk-ighylafootabtuthwueirmoycccyqtdgbifyhozduvolkdyt
|
||||
base_url: https://api.siliconflow.cn/v1/
|
||||
max_tokens: 4096
|
||||
temperature: 1.0
|
||||
@@ -138,7 +137,7 @@ models:
|
||||
display_name: inclusionAI/Ling-flash-2.0
|
||||
use: langchain_openai:ChatOpenAI
|
||||
model: inclusionAI/Ling-flash-2.0
|
||||
api_key: sk-ighylafootabtuthwueirmoycccyqtdgbifyhozduvolkdyt
|
||||
api_key: sk-ighylafootabtuthwueirmoycccyqtdgbifyhozduvolkdyt
|
||||
base_url: https://api.siliconflow.cn/v1/
|
||||
max_tokens: 4096
|
||||
temperature: 1.0
|
||||
@@ -148,7 +147,7 @@ models:
|
||||
display_name: deepseek-ai/DeepSeek-V4-Pro
|
||||
use: langchain_openai:ChatOpenAI
|
||||
model: deepseek-ai/DeepSeek-V4-Pro
|
||||
api_key: sk-ighylafootabtuthwueirmoycccyqtdgbifyhozduvolkdyt
|
||||
api_key: sk-ighylafootabtuthwueirmoycccyqtdgbifyhozduvolkdyt
|
||||
base_url: https://api.siliconflow.cn/v1/
|
||||
max_tokens: 4096
|
||||
temperature: 1.0
|
||||
@@ -254,14 +253,14 @@ skills:
|
||||
skill_evolution:
|
||||
enabled: true
|
||||
curator:
|
||||
enabled: true # 每 24 小时自动清理 + 合并 skill
|
||||
enabled: true # 每 24 小时自动清理 + 合并 skill
|
||||
interval_hours: 24
|
||||
review_worker:
|
||||
enabled: true # 被动复盘开关
|
||||
min_tool_calls: 5 # 触发阈值:本轮至少 5 次工具调用,与 prompt 中"≥5 步"硬条件一致
|
||||
max_messages: 60 # 传给 LLM 的最大消息条数
|
||||
timeout_seconds: 120 # 单次 review 超时(秒)
|
||||
model_name: # 留空则使用主模型
|
||||
enabled: true # 被动复盘开关
|
||||
min_tool_calls: 5 # 触发阈值:本轮至少 5 次工具调用,与 prompt 中"≥5 步"硬条件一致
|
||||
max_messages: 60 # 传给 LLM 的最大消息条数
|
||||
timeout_seconds: 120 # 单次 review 超时(秒)
|
||||
model_name: # 留空则使用主模型
|
||||
|
||||
agents_api:
|
||||
enabled: true
|
||||
@@ -272,31 +271,30 @@ auth_login:
|
||||
# 口令不对直接 401。password 留空则默认口令为 123ewq。仅作用于用户名直登。
|
||||
username_login:
|
||||
require_password: false
|
||||
password: ""
|
||||
password: ''
|
||||
# token 换登录:前端用 ?authToken=上游token 进入,后端调用 token_info_url
|
||||
# (把该 token 直接拼成 Authorization: Bearer <token> 头)换出用户名,再登录;
|
||||
# 用户名不在库里时自动注册。
|
||||
token_login:
|
||||
enabled: false
|
||||
token_info_url: "https://ch1.b.uat.4.cn/consumer/login/getTokenInfo"
|
||||
token_info_url: 'https://ch1.b.uat.4.cn/consumer/login/getTokenInfo'
|
||||
# 已弃用:鉴权头现由前端传入的 token 拼成 "Bearer <token>",此项不再生效,保留仅兼容。
|
||||
service_authorization: "Bearer admin"
|
||||
service_authorization: 'Bearer admin'
|
||||
timeout_seconds: 10
|
||||
# 上游是 HTTPS。UAT/内网常用自签或私有 CA 证书,默认 verify=true 会握手失败导致
|
||||
# 永远 401。此处 uat 域名按自签处理,先关校验;生产请置 true 或配 ca_cert_path。
|
||||
verify_ssl: false
|
||||
ca_cert_path: "" # 可选:PEM 格式 CA 包路径,设置后优先生效并启用校验
|
||||
ca_cert_path: '' # 可选:PEM 格式 CA 包路径,设置后优先生效并启用校验
|
||||
|
||||
# 日志系统入口(仅管理员可见):右下角「设置」菜单中会多出一个「日志系统」入口,
|
||||
# 点击后在新标签页打开下面的 url。enabled 关掉则不显示该入口。
|
||||
|
||||
|
||||
database:
|
||||
backend: sqlite
|
||||
sqlite_dir: .deer-flow/data
|
||||
pool_size: 20 # 基础连接池(postgres/mysql 生效;sqlite 忽略)
|
||||
max_overflow: 20 # 高峰期可临时超出 pool_size 的额外连接数,真实上限 = pool_size + max_overflow
|
||||
pool_timeout: 30 # 池满时等待空闲连接的秒数,超时报错
|
||||
pool_size: 20 # 基础连接池(postgres/mysql 生效;sqlite 忽略)
|
||||
max_overflow: 20 # 高峰期可临时超出 pool_size 的额外连接数,真实上限 = pool_size + max_overflow
|
||||
pool_timeout: 30 # 池满时等待空闲连接的秒数,超时报错
|
||||
echo_sql: false
|
||||
|
||||
checkpointer:
|
||||
@@ -308,35 +306,38 @@ checkpointer:
|
||||
# users/{user_id}/memory_config.json > .deer-flow/memory_user_overrides.json > 此处
|
||||
memory:
|
||||
enabled: true
|
||||
version: v1 # 记忆版本: 'v1'(原版 DeerFlow, memory.json + LLM 自动提取)
|
||||
# 'v2'(USER.md/MEMORY.md + 可选 Hindsight)
|
||||
provider: hindsight # 'builtin' | 'hindsight'(外部 provider 名)
|
||||
# builtin 始终启用,这里只决定 external 选哪个
|
||||
# (version=v1 时此字段忽略)
|
||||
version:
|
||||
v1 # 记忆版本: 'v1'(原版 DeerFlow, memory.json + LLM 自动提取)
|
||||
# 'v2'(USER.md/MEMORY.md + 可选 Hindsight)
|
||||
provider:
|
||||
hindsight # 'builtin' | 'hindsight'(外部 provider 名)
|
||||
# builtin 始终启用,这里只决定 external 选哪个
|
||||
# (version=v1 时此字段忽略)
|
||||
|
||||
# V1 专属配置 —— version=v1 时生效
|
||||
v1:
|
||||
max_facts: 100 # 最多保留的事实条数,超出时驱逐最低置信度的事实
|
||||
max_facts: 100 # 最多保留的事实条数,超出时驱逐最低置信度的事实
|
||||
fact_confidence_threshold: 0.7 # 事实置信度阈值,低于此值不保存
|
||||
debounce_seconds: 30 # 对话结束后延迟多少秒才触发 LLM 提取
|
||||
model_name: "" # 用于事实提取的 LLM 模型名;空则继承全局默认模型
|
||||
token_budget: 2000 # 注入系统提示词的 token 预算
|
||||
debounce_seconds: 30 # 对话结束后延迟多少秒才触发 LLM 提取
|
||||
model_name: '' # 用于事实提取的 LLM 模型名;空则继承全局默认模型
|
||||
token_budget: 2000 # 注入系统提示词的 token 预算
|
||||
builtin:
|
||||
enabled: true
|
||||
memory_char_limit: 2200
|
||||
user_char_limit: 1375
|
||||
deduplicate_on_load: true
|
||||
|
||||
hindsight: # provider=hindsight 时生效,需另行部署 Hindsight 服务
|
||||
mode: local_external # 'cloud' | 'local_embedded' | 'local_external'
|
||||
hindsight: # provider=hindsight 时生效,需另行部署 Hindsight 服务
|
||||
mode: local_external # 'cloud' | 'local_embedded' | 'local_external'
|
||||
api_url: http://47.88.25.99:18888
|
||||
api_key: "" # 部署 Hindsight 后填,或改成 $HINDSIGHT_API_KEY 并设同名环境变量
|
||||
# 注意:写成 $VAR 但环境变量未设置会导致配置加载失败
|
||||
bank_id_template: "deerflow-user-{user_id}"
|
||||
work_bank_id_template: "deerflow-work-{user_id}-{agent_id}"
|
||||
api_key:
|
||||
'' # 部署 Hindsight 后填,或改成 $HINDSIGHT_API_KEY 并设同名环境变量
|
||||
# 注意:写成 $VAR 但环境变量未设置会导致配置加载失败
|
||||
bank_id_template: 'deerflow-user-{user_id}'
|
||||
work_bank_id_template: 'deerflow-work-{user_id}-{agent_id}'
|
||||
memory_mode: context # 'context' | 'tools' | 'hybrid'
|
||||
bank_mission: "你是一个中文记忆助手,负责从对话中提炼和存储重要信息。所有记忆内容必须使用中文记录。"
|
||||
bank_retain_mission: "请从以下对话中提炼重要信息,包括用户的偏好、需求、背景知识和关键事实。所有提炼的内容必须用中文表达。"
|
||||
bank_mission: '你是一个中文记忆助手,负责从对话中提炼和存储重要信息。所有记忆内容必须使用中文记录。'
|
||||
bank_retain_mission: '请从以下对话中提炼重要信息,包括用户的偏好、需求、背景知识和关键事实。所有提炼的内容必须用中文表达。'
|
||||
recall_budget: mid # 'low' | 'mid' | 'high'
|
||||
recall_max_tokens: 4096
|
||||
recall_max_input_chars: 800
|
||||
@@ -344,8 +345,8 @@ memory:
|
||||
auto_retain: true
|
||||
retain_async: true
|
||||
retain_every_n_turns: 1
|
||||
retain_user_prefix: "User"
|
||||
retain_assistant_prefix: "Assistant"
|
||||
retain_user_prefix: 'User'
|
||||
retain_assistant_prefix: 'Assistant'
|
||||
|
||||
# background_extraction:预留功能,代码尚未实现 —— 仅设计文档存在。
|
||||
# 待对应版本支持后,取消下面整段注释即可启用(漏记兜底)。
|
||||
@@ -363,7 +364,7 @@ memory:
|
||||
max_tokens: 2000
|
||||
include_builtin: true
|
||||
include_hindsight: true
|
||||
context_tag: "memory-context" # 包裹 Hindsight recall 的标签名
|
||||
context_tag: 'memory-context' # 包裹 Hindsight recall 的标签名
|
||||
|
||||
security:
|
||||
scan_content: true # 注入/外渗模式扫描
|
||||
@@ -381,5 +382,5 @@ ai_writing:
|
||||
|
||||
log_system:
|
||||
enabled: true
|
||||
url: "https://your-log-system.example.com"
|
||||
label: "日志系统"
|
||||
url: 'https://your-log-system.example.com'
|
||||
label: '日志系统'
|
||||
Reference in new issue
Block a user