docs(codebase): generate codebase map
This commit is contained in:
parent
6b900ccb60
commit
6411b3d7a0
|
|
@ -0,0 +1,141 @@
|
||||||
|
# 架构分析
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-07
|
||||||
|
|
||||||
|
## 模式概览
|
||||||
|
|
||||||
|
**Overall:** 分层单体 + 前后端分离 + 运行时内核(Harness)与应用壳层(App)拆分
|
||||||
|
|
||||||
|
**Key Characteristics:**
|
||||||
|
- 后端采用 `Harness(Core)` 与 `Gateway/Channels(App)` 分层,依赖方向固定为 `app.* -> deerflow.*`,反向依赖禁止(见 `backend/docs/HARNESS_APP_SPLIT.md`)
|
||||||
|
- 前端采用 Next.js App Router,页面层(`src/app`)与领域能力层(`src/core`)分离,UI 组件集中在 `src/components`
|
||||||
|
- 运行时通过单例对象管理(`RunManager`、`StreamBridge`、`checkpointer`、`store`),由网关生命周期统一初始化(`backend/app/gateway/deps.py`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
当前架构边界清晰,后续规划应优先沿“Gateway 负责协议与路由、Harness 负责运行时与智能体能力、Frontend core 负责数据访问”的既有分层扩展,避免跨层直接调用。
|
||||||
|
|
||||||
|
## 分层设计
|
||||||
|
|
||||||
|
**前端展示与路由层(Next App Router):**
|
||||||
|
- Purpose: 负责页面路由、布局装配、页面级 Provider 注入
|
||||||
|
- Location: `frontend/src/app`
|
||||||
|
- Contains: `layout.tsx`、`page.tsx`、`workspace/*`、`api/*` Route Handler
|
||||||
|
- Depends on: `frontend/src/components`、`frontend/src/core`、`frontend/src/server`
|
||||||
|
- Used by: 浏览器请求与 Next.js 运行时
|
||||||
|
|
||||||
|
**前端领域能力层(Core):**
|
||||||
|
- Purpose: 负责 API 客户端、流式会话、线程管理、上传、设置与 i18n 逻辑
|
||||||
|
- Location: `frontend/src/core`
|
||||||
|
- Contains: `core/threads/hooks.ts`、`core/api/api-client.ts`、`core/*/api.ts|hooks.ts`
|
||||||
|
- Depends on: `@langchain/langgraph-sdk`、`@tanstack/react-query`、后端 API
|
||||||
|
- Used by: `frontend/src/components/workspace/*` 与页面组件
|
||||||
|
|
||||||
|
**后端 API 网关层(App Gateway):**
|
||||||
|
- Purpose: 负责 HTTP 协议适配、路由聚合、SSE 输出、线程与运行生命周期接口
|
||||||
|
- Location: `backend/app/gateway`
|
||||||
|
- Contains: `app.py`、`deps.py`、`services.py`、`routers/*.py`
|
||||||
|
- Depends on: `deerflow.runtime`、`deerflow.config`、`deerflow.agents`
|
||||||
|
- Used by: 前端、第三方客户端、IM 渠道服务
|
||||||
|
|
||||||
|
**后端 IM 渠道层(App Channels):**
|
||||||
|
- Purpose: 负责飞书/Slack/Telegram 等外部消息通道接入与消息转发
|
||||||
|
- Location: `backend/app/channels`
|
||||||
|
- Contains: `service.py`、`manager.py`、`feishu.py`、`slack.py`、`telegram.py`
|
||||||
|
- Depends on: `deerflow` 核心能力与 Gateway 配置
|
||||||
|
- Used by: 网关生命周期在启动阶段触发(`backend/app/gateway/app.py`)
|
||||||
|
|
||||||
|
**后端运行时内核层(Harness):**
|
||||||
|
- Purpose: 负责 Agent 构建、Middleware 编排、工具系统、运行时状态与流桥接
|
||||||
|
- Location: `backend/packages/harness/deerflow`
|
||||||
|
- Contains: `agents/`、`runtime/`、`tools/`、`sandbox/`、`skills/`、`models/`、`config/`
|
||||||
|
- Depends on: LangChain/LangGraph 与基础设施依赖
|
||||||
|
- Used by: `backend/app/gateway/*` 与潜在 SDK/CLI 调用
|
||||||
|
|
||||||
|
## 关键数据/控制流
|
||||||
|
|
||||||
|
**Flow 1: Web 会话流式对话(主链路)**
|
||||||
|
1. 前端聊天页通过 `useThreadStream` 发起 `runs.stream`(`frontend/src/core/threads/hooks.ts`)
|
||||||
|
2. LangGraph SDK 客户端调用网关流式接口(`frontend/src/core/api/api-client.ts` -> `/api/langgraph`)
|
||||||
|
3. Gateway 路由进入 `thread_runs.py` 或 `runs.py`,委派 `start_run`(`backend/app/gateway/routers/thread_runs.py`, `backend/app/gateway/services.py`)
|
||||||
|
4. `start_run` 创建 RunRecord 并启动后台任务,运行 `make_lead_agent` 构建的 Agent 图(`backend/packages/harness/deerflow/agents/lead_agent/agent.py`)
|
||||||
|
5. 运行时事件通过 `MemoryStreamBridge` 发布,`sse_consumer` 序列化为 SSE 推送到前端(`backend/packages/harness/deerflow/runtime/stream_bridge/memory.py`)
|
||||||
|
6. 前端 `useStream` 消费增量状态,刷新消息、标题、子任务与线程列表缓存(`frontend/src/core/threads/hooks.ts`)
|
||||||
|
|
||||||
|
**Flow 2: 线程生命周期与状态持久化**
|
||||||
|
1. 前端线程列表调用 `threads.search`,线程详情页读取/更新状态(`frontend/src/core/threads/hooks.ts`)
|
||||||
|
2. Gateway `threads.py` 通过 `store` + `checkpointer` 读写线程元数据与 checkpoint
|
||||||
|
3. run 完成后,服务层将 checkpoint 中的标题回写线程 store(`_sync_thread_title_after_run`,`backend/app/gateway/services.py`)
|
||||||
|
|
||||||
|
**Flow 3: 前端 API 代理转发(非 LangGraph SDK 路径)**
|
||||||
|
1. 前端 Route Handler 接收 `/api/memory/*` 请求(`frontend/src/app/api/memory/[...path]/route.ts`)
|
||||||
|
2. 直接代理至 `NEXT_PUBLIC_BACKEND_BASE_URL` 对应网关地址
|
||||||
|
3. Gateway 处理并返回,前端透明透传响应头与响应体
|
||||||
|
|
||||||
|
**State Management:**
|
||||||
|
- 前端 UI 状态:React State + Context(例如 `ArtifactsProvider`、`SubtasksProvider`)
|
||||||
|
- 前端服务端状态:React Query(线程列表、突变后失效重取)
|
||||||
|
- 后端运行状态:`RunManager` 内存注册表(运行中任务)
|
||||||
|
- 后端持久状态:LangGraph checkpointer + store(线程状态、checkpoint、元数据)
|
||||||
|
|
||||||
|
## 关键抽象
|
||||||
|
|
||||||
|
**Run 生命周期抽象(RunManager + RunRecord):**
|
||||||
|
- Purpose: 统一 run 的创建、冲突策略、取消、状态迁移
|
||||||
|
- Examples: `backend/packages/harness/deerflow/runtime/runs/manager.py`
|
||||||
|
- Pattern: 内存注册表 + asyncio 锁保护并发一致性
|
||||||
|
|
||||||
|
**流桥接抽象(StreamBridge):**
|
||||||
|
- Purpose: 将后台执行事件转换为可订阅的事件流
|
||||||
|
- Examples: `backend/packages/harness/deerflow/runtime/stream_bridge/base.py`, `backend/packages/harness/deerflow/runtime/stream_bridge/memory.py`
|
||||||
|
- Pattern: 每 run 一条队列 + END/HEARTBEAT 哨兵事件
|
||||||
|
|
||||||
|
**Agent 组装抽象(make_lead_agent / create_deerflow_agent):**
|
||||||
|
- Purpose: 基于配置与上下文动态装配模型、工具与 middleware 链
|
||||||
|
- Examples: `backend/packages/harness/deerflow/agents/lead_agent/agent.py`, `backend/packages/harness/deerflow/agents/factory.py`
|
||||||
|
- Pattern: “配置驱动 + 有序中间件管线 + 条件启用能力”
|
||||||
|
|
||||||
|
**前端会话编排抽象(useThreadStream):**
|
||||||
|
- Purpose: 屏蔽流式协议细节,提供统一发送消息/停止运行/状态更新能力
|
||||||
|
- Examples: `frontend/src/core/threads/hooks.ts`
|
||||||
|
- Pattern: Hook 封装 SDK + optimistic UI + query cache 同步
|
||||||
|
|
||||||
|
## 关键入口
|
||||||
|
|
||||||
|
**Gateway 入口:**
|
||||||
|
- Location: `backend/app/gateway/app.py`
|
||||||
|
- Triggers: `uvicorn app.gateway.app:app`(见 `backend/Makefile`)
|
||||||
|
- Responsibilities: 应用启动、router 装配、生命周期内 runtime 单例初始化
|
||||||
|
|
||||||
|
**Gateway 运行时依赖入口:**
|
||||||
|
- Location: `backend/app/gateway/deps.py`
|
||||||
|
- Triggers: FastAPI lifespan 调用 `langgraph_runtime`
|
||||||
|
- Responsibilities: 创建/销毁 `stream_bridge`、`checkpointer`、`store`、`run_manager`
|
||||||
|
|
||||||
|
**前端根入口:**
|
||||||
|
- Location: `frontend/src/app/layout.tsx`
|
||||||
|
- Triggers: Next.js App Router 根布局渲染
|
||||||
|
- Responsibilities: 注入主题与 i18n Provider
|
||||||
|
|
||||||
|
**前端工作台入口:**
|
||||||
|
- Location: `frontend/src/app/workspace/layout.tsx`, `frontend/src/app/workspace/chats/[thread_id]/page.tsx`
|
||||||
|
- Triggers: 访问 `/workspace/*`
|
||||||
|
- Responsibilities: QueryClient 注入、侧边栏控制、聊天线程交互
|
||||||
|
|
||||||
|
## 错误处理策略
|
||||||
|
|
||||||
|
**Strategy:** 分层兜底 + 协议一致化
|
||||||
|
|
||||||
|
**Patterns:**
|
||||||
|
- 路由层用 HTTP 状态码表达失败,依赖层缺失返回 503(`backend/app/gateway/deps.py`)
|
||||||
|
- 流式执行失败统一在服务层记录并通过 SSE/最终状态输出(`backend/app/gateway/services.py`)
|
||||||
|
- 前端流式错误统一 toast 呈现并清理 optimistic 状态(`frontend/src/core/threads/hooks.ts`)
|
||||||
|
|
||||||
|
## 跨切面关注点
|
||||||
|
|
||||||
|
**Logging:** 后端在网关入口统一配置 logging,模块内按 `logger` 输出(`backend/app/gateway/app.py`)
|
||||||
|
**Validation:** 请求模型使用 Pydantic;运行配置做字段规整(如 `normalize_stream_modes`、`build_run_config`)
|
||||||
|
**Authentication:** 前端通过 `better-auth` 路由处理认证(`frontend/src/app/api/auth/[...all]/route.ts`, `frontend/src/server/better-auth/*`);网关核心 API 当前以部署侧网关/Nginx 控制为主
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Architecture analysis: 2026-04-07*
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
# Codebase Concerns
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-07
|
||||||
|
|
||||||
|
## 简短结论
|
||||||
|
|
||||||
|
当前代码库后端能力完整、测试数量较多,但在“生产安全基线”和“运行时一致性”上存在高优先级缺口:API 鉴权缺失、回滚语义未闭环、流式事件链路缺少可恢复能力。前端主要问题是关键模块体量偏大与测试覆盖不均衡,短期会拖慢迭代速度,中期会放大回归风险。
|
||||||
|
|
||||||
|
## 优先级建议(面向规划)
|
||||||
|
|
||||||
|
- P0(立即):补齐网关鉴权与访问控制;补全 rollback 真回滚语义。
|
||||||
|
- P1(近期):修复消息角色归一化错误;完善 SSE 可恢复性与丢事件观测。
|
||||||
|
- P2(排期):拆分超大前端组件、收敛 demo 静态资源体积、减少“声明支持但未实现”的 API 选项。
|
||||||
|
|
||||||
|
## Tech Debt
|
||||||
|
|
||||||
|
**运行时回滚语义未实现(高优先级):**
|
||||||
|
- Issue: 取消 run 时支持 `action=rollback`,但实际未执行 checkpoint 回滚,仅记录日志并 `pass`。
|
||||||
|
- Files: `backend/packages/harness/deerflow/runtime/runs/worker.py`
|
||||||
|
- Impact: 前端/调用方会认为“已回滚”,但线程状态可能仍保留部分中间写入,导致状态一致性问题。
|
||||||
|
- Fix approach: 在 `rollback` 分支接入 checkpointer 的真实回退 API(按 `pre_run_checkpoint_id` 恢复),并补充回滚前后状态断言测试(成功、失败、并发取消三类)。
|
||||||
|
|
||||||
|
**后端代码布局存在“空 src + 实际实现在 packages”认知负债(中优先级):**
|
||||||
|
- Issue: 业务实现集中在 `backend/packages/harness/deerflow/`,而 `backend/src/` 仅有缓存产物目录结构,容易误导新贡献者。
|
||||||
|
- Files: `backend/packages/harness/deerflow/`, `backend/src/`
|
||||||
|
- Impact: 新代码落点不稳定、审查成本上升、重构时容易出现重复实现。
|
||||||
|
- Fix approach: 在贡献文档和目录说明中明确“单一真实源码根”;清理或显式标注 `backend/src/` 的用途,避免“影子目录”持续存在。
|
||||||
|
|
||||||
|
**前端关键组件体量过大(中优先级):**
|
||||||
|
- Issue: 交互核心组件单文件体量偏大,状态/视图/副作用耦合。
|
||||||
|
- Files: `frontend/src/components/ai-elements/prompt-input.tsx`, `frontend/src/components/workspace/input-box.tsx`, `frontend/src/components/workspace/artifacts/artifact-file-detail.tsx`
|
||||||
|
- Impact: 修改单一功能易触发连带回归,评审与测试成本高。
|
||||||
|
- Fix approach: 以“状态管理、上传/附件、动作菜单、发送流程”拆分子模块;每次拆分同步补充组件级测试。
|
||||||
|
|
||||||
|
## Known Bugs
|
||||||
|
|
||||||
|
**消息角色被错误归一化为 HumanMessage(高优先级):**
|
||||||
|
- Symptoms: 非 `user/human` 的消息(如 system/ai/tool)在输入归一化中被降级为 `HumanMessage`。
|
||||||
|
- Files: `backend/app/gateway/services.py`
|
||||||
|
- Trigger: `normalize_input()` 处理 `messages` 列表时遇到非用户角色。
|
||||||
|
- Workaround: 调用端仅传用户消息;系统消息改走其他配置通道。
|
||||||
|
|
||||||
|
**artifact 文本判定后仍可能触发 UTF-8 解码异常(中优先级):**
|
||||||
|
- Symptoms: 文件被判定为“文本”后直接 `read_text(encoding="utf-8")`,遇到非 UTF-8 内容可能返回 500。
|
||||||
|
- Files: `backend/app/gateway/routers/artifacts.py`
|
||||||
|
- Trigger: `is_text_file_by_content()` 返回 true,但实际编码非 UTF-8。
|
||||||
|
- Workaround: 使用 `download=true` 强制下载,避免 inline 文本解码路径。
|
||||||
|
|
||||||
|
**API 声明支持 `enqueue` 但运行时不支持(中优先级):**
|
||||||
|
- Symptoms: 请求模型允许 `multitask_strategy="enqueue"`,但运行时抛 `UnsupportedStrategyError`(501)。
|
||||||
|
- Files: `backend/app/gateway/routers/thread_runs.py`, `backend/packages/harness/deerflow/runtime/runs/manager.py`
|
||||||
|
- Trigger: 客户端按 schema 传入 `enqueue`。
|
||||||
|
- Workaround: 客户端仅使用 `reject|interrupt|rollback`。
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
**网关缺少统一鉴权/鉴别层(高优先级):**
|
||||||
|
- Risk: 线程、上传、技能、memory、run 控制等接口可被未授权调用(取决于外围网络暴露)。
|
||||||
|
- Files: `backend/app/gateway/app.py`, `backend/app/gateway/routers/*.py`
|
||||||
|
- Current mitigation: 注释说明依赖外层 nginx;代码内无显式 `Depends` 鉴权依赖。
|
||||||
|
- Recommendations: 在网关层增加统一认证中间件(JWT/API Key/Session 任一),并对高风险写操作路由做细粒度授权。
|
||||||
|
|
||||||
|
**本地 host bash 仅“尽力防护”,非强隔离(中高优先级):**
|
||||||
|
- Risk: 启用 `allow_host_bash` 后,命令路径校验强调 best-effort,且对 bash 写入限制不等同于读写工具限制。
|
||||||
|
- Files: `backend/packages/harness/deerflow/sandbox/tools.py`
|
||||||
|
- Current mitigation: 绝对路径校验、路径遍历检查、file:// 阻断、虚拟路径替换。
|
||||||
|
- Recommendations: 将 host bash 默认硬禁用;在生产配置强制容器沙箱;增加审计日志与策略开关(按工具/命令白名单)。
|
||||||
|
|
||||||
|
## Performance Bottlenecks
|
||||||
|
|
||||||
|
**流式桥接队列容量有限且存在丢事件(中优先级):**
|
||||||
|
- Problem: 单 run 队列默认上限 256;发布超时会丢事件,且仅日志告警。
|
||||||
|
- Files: `backend/packages/harness/deerflow/runtime/stream_bridge/memory.py`
|
||||||
|
- Cause: 内存队列 + 固定容量 + 没有持久化重放。
|
||||||
|
- Improvement path: 引入可重放后端(Redis/持久队列)或增大可配置容量;将 dropped_count 暴露为指标并设置告警阈值。
|
||||||
|
|
||||||
|
**前端仓库包含较大 demo 资产,影响构建/分发体积(中优先级):**
|
||||||
|
- Problem: `frontend/public/demo/` 包含较多图片/视频与线程快照。
|
||||||
|
- Files: `frontend/public/demo/threads/**`
|
||||||
|
- Cause: demo 内容直接入仓并随静态资源参与交付。
|
||||||
|
- Improvement path: 将大型 demo 资产迁移到对象存储/CDN 或按环境开关构建;保留最小样例集。
|
||||||
|
|
||||||
|
## Fragile Areas
|
||||||
|
|
||||||
|
**Run 生命周期与 SSE 消费链路耦合(中高优先级):**
|
||||||
|
- Files: `backend/app/gateway/services.py`, `backend/app/gateway/routers/thread_runs.py`, `backend/packages/harness/deerflow/runtime/runs/manager.py`, `backend/packages/harness/deerflow/runtime/stream_bridge/memory.py`
|
||||||
|
- Why fragile: 断线策略、取消语义、状态迁移、队列清理分散在多处,边界行为(断线+取消+重连)容易退化。
|
||||||
|
- Safe modification: 先补“状态机契约测试”再改逻辑;对 `cancel/rollback/interrupt` 统一建表驱动测试。
|
||||||
|
- Test coverage: 后端测试较多,但“断线重连 + 事件重放 + 回滚一致性”端到端场景仍有缺口。
|
||||||
|
|
||||||
|
**前端输入与工件详情模块变更风险高(中优先级):**
|
||||||
|
- Files: `frontend/src/components/workspace/input-box.tsx`, `frontend/src/components/ai-elements/prompt-input.tsx`, `frontend/src/components/workspace/artifacts/artifact-file-detail.tsx`
|
||||||
|
- Why fragile: 单文件承担过多职责,状态路径复杂。
|
||||||
|
- Safe modification: 采用“先抽 hooks/子组件,后迁移调用点”的两阶段改造;每步保留行为快照测试。
|
||||||
|
- Test coverage: `frontend/src/` 下单元测试文件较少(仅少量),复杂交互主要依赖 E2E。
|
||||||
|
|
||||||
|
## Scaling Limits
|
||||||
|
|
||||||
|
**Run/Stream 元数据以内存为中心,重启后状态不连续(中高优先级):**
|
||||||
|
- Current capacity: 单进程内存字典 + 队列;run 记录会延迟清理,stream 事件不支持回放。
|
||||||
|
- Limit: 进程重启或横向扩容后,`Last-Event-ID` 无法恢复历史事件;跨实例一致性弱。
|
||||||
|
- Files: `backend/packages/harness/deerflow/runtime/runs/manager.py`, `backend/packages/harness/deerflow/runtime/stream_bridge/memory.py`
|
||||||
|
- Scaling path: 引入跨实例共享存储(持久 run registry + 可回放事件流),并将 `last_event_id` 变为可用恢复机制。
|
||||||
|
|
||||||
|
## Dependencies at Risk
|
||||||
|
|
||||||
|
**前端依赖面较宽,升级波动风险上升(中优先级):**
|
||||||
|
- Risk: UI/渲染/动画/编辑器与 AI SDK 依赖较多,任一主版本变化可能触发连锁适配。
|
||||||
|
- Impact: 构建稳定性与行为一致性风险上升。
|
||||||
|
- Files: `frontend/package.json`
|
||||||
|
- Migration plan: 建立“核心依赖分层升级策略”(渲染内核、AI SDK、UI 库分批升级)与最小回归清单。
|
||||||
|
|
||||||
|
## Missing Critical Features
|
||||||
|
|
||||||
|
**后端 API 层缺少内建访问控制能力(高优先级):**
|
||||||
|
- Problem: 关键写操作接口缺少统一认证与授权依赖。
|
||||||
|
- Blocks: 无法安全对公网或多租户环境直接暴露网关。
|
||||||
|
- Files: `backend/app/gateway/app.py`, `backend/app/gateway/routers/*.py`
|
||||||
|
|
||||||
|
**SSE 可恢复协议未形成闭环(中高优先级):**
|
||||||
|
- Problem: 桥接层注明接受 `last_event_id` 但忽略重放。
|
||||||
|
- Blocks: 客户端断线恢复体验与长任务稳定性。
|
||||||
|
- Files: `backend/packages/harness/deerflow/runtime/stream_bridge/memory.py`
|
||||||
|
|
||||||
|
## Test Coverage Gaps
|
||||||
|
|
||||||
|
**前端复杂交互缺少充分单元/组件测试(中优先级):**
|
||||||
|
- What's not tested: 输入框状态机、附件生命周期、artifact 详情多分支渲染的细粒度行为。
|
||||||
|
- Files: `frontend/src/components/workspace/input-box.tsx`, `frontend/src/components/ai-elements/prompt-input.tsx`, `frontend/src/components/workspace/artifacts/artifact-file-detail.tsx`
|
||||||
|
- Risk: 小改动引发 UI 行为回归且难快速定位。
|
||||||
|
- Priority: High
|
||||||
|
|
||||||
|
**安全基线测试缺少“未认证访问”负向用例(高优先级):**
|
||||||
|
- What's not tested: 未携带认证凭据访问关键 API 的拒绝路径(当前实现层面未内建)。
|
||||||
|
- Files: `backend/app/gateway/routers/*.py`, `backend/tests/`
|
||||||
|
- Risk: 安全能力依赖部署外部组件,环境漂移即暴露风险。
|
||||||
|
- Priority: High
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Concerns audit: 2026-04-07*
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
# Coding Conventions
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-07
|
||||||
|
|
||||||
|
## Naming Patterns
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Python 使用 `snake_case.py`,按领域分层放置,例如 `backend/packages/harness/deerflow/config/app_config.py`、`backend/packages/harness/deerflow/agents/lead_agent/agent.py`。
|
||||||
|
- Backend 测试文件统一 `test_*.py`,位于 `backend/tests/`,例如 `backend/tests/test_client.py`、`backend/tests/test_stream_bridge.py`。
|
||||||
|
- Frontend 页面与组件文件使用 `kebab-case.tsx` 或目录约定命名,例如 `frontend/src/app/workspace/page.tsx`、`frontend/src/components/workspace/workspace-container.tsx`。
|
||||||
|
- Frontend E2E 测试使用 `*.spec.ts`,位于 `frontend/tests/e2e/`;轻量模块测试使用 `*.test.ts` 或 `*.test.mjs`,例如 `frontend/src/core/api/stream-mode.test.ts`。
|
||||||
|
|
||||||
|
**Functions:**
|
||||||
|
- Python 函数与内部 helper 统一 `snake_case`,例如 `_make_e2e_config`(`backend/tests/test_client_e2e.py`)、`get_available_tools`(`backend/packages/harness/deerflow/tools/tools.py`)。
|
||||||
|
- TypeScript/JavaScript 函数统一 `camelCase`,例如 `copyToClipboard`(`frontend/src/lib/utils.ts`)、`skipIfMissingThread`(`frontend/tests/e2e/support/chat-helpers.ts`)。
|
||||||
|
|
||||||
|
**Variables:**
|
||||||
|
- Python 常量使用全大写下划线,如 `BUILTIN_TOOLS`(`backend/packages/harness/deerflow/tools/tools.py`)。
|
||||||
|
- TS 常量通常 `camelCase`,跨测试配置使用全大写语义常量,如 `THREAD_FOR_WELCOME`(`frontend/tests/e2e/support/chat-helpers.ts`)。
|
||||||
|
|
||||||
|
**Types:**
|
||||||
|
- Python 使用类型注解(`list[str]`、`dict[str, Any]`)与 `pydantic` 模型,见 `backend/packages/harness/deerflow/config/app_config.py`。
|
||||||
|
- Frontend 使用 TypeScript 严格模式,并偏向显式返回类型(例如 `Promise<void>` in `frontend/src/lib/utils.ts`)。
|
||||||
|
|
||||||
|
## Code Style
|
||||||
|
|
||||||
|
**Formatting:**
|
||||||
|
- Backend 使用 `ruff format`;规则来源 `backend/ruff.toml`(`quote-style = "double"`,`indent-style = "space"`,`line-length = 240`)。
|
||||||
|
- Frontend 使用 `prettier` + `prettier-plugin-tailwindcss`,配置在 `frontend/prettier.config.js`;CI 中执行 `pnpm format`(check 模式)。
|
||||||
|
|
||||||
|
**Linting:**
|
||||||
|
- Backend 通过 `ruff check .`,启用 `E/F/I/UP`(`backend/ruff.toml`)。
|
||||||
|
- Frontend 通过 `eslint` flat config(`frontend/eslint.config.js`),叠加 `next/core-web-vitals` 与 `typescript-eslint` type-checked 规则。
|
||||||
|
- Frontend 强制导入顺序(`import/order`)与分组换行,内部别名 `@/**` 归类为 internal。
|
||||||
|
|
||||||
|
## Import Organization
|
||||||
|
|
||||||
|
**Order:**
|
||||||
|
1. 标准库/内建模块(如 `import os`、`import path from "path"`)。
|
||||||
|
2. 第三方依赖(如 `from pydantic import BaseModel`、`import { expect, test } from "@playwright/test"`)。
|
||||||
|
3. 项目内部模块(如 `from deerflow...`、`from "@/env"`)。
|
||||||
|
|
||||||
|
**Path Aliases:**
|
||||||
|
- Frontend 启用 `@/* -> ./src/*`(`frontend/tsconfig.json`);新增代码应优先使用该别名替代跨层级相对路径。
|
||||||
|
- Backend 无类似别名约定;使用包内绝对导入 `deerflow.*`(见 `backend/packages/harness/deerflow/client.py`)。
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
**Patterns:**
|
||||||
|
- Backend 在参数/配置非法时直接抛出 `ValueError` / `FileNotFoundError`,示例见 `backend/packages/harness/deerflow/config/app_config.py` 和 `backend/packages/harness/deerflow/client.py`。
|
||||||
|
- Backend 在可降级场景使用 `try/except` + `logger.warning/error`,不中断主流程(例如 MCP/ACP 工具加载,`backend/packages/harness/deerflow/tools/tools.py`)。
|
||||||
|
- Frontend 偏向显式 guard + return(例如 `frontend/src/app/workspace/page.tsx` 的条件重定向)。
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
**Framework:** `logging`(Python) + `console`(Frontend 局部)
|
||||||
|
|
||||||
|
**Patterns:**
|
||||||
|
- Backend 统一模块级 `logger = logging.getLogger(__name__)`,记录关键分支、fallback、装载结果(`backend/packages/harness/deerflow/tools/tools.py`)。
|
||||||
|
- Frontend 存在业务调试日志(`console.log` / `console.warn`)用于 iframe 与失败分支,见 `frontend/src/lib/utils.ts`、`frontend/src/core/uploads/prompt-input-files.test.mjs`(通过 mock 断言 warning)。
|
||||||
|
|
||||||
|
## Comments
|
||||||
|
|
||||||
|
**When to Comment:**
|
||||||
|
- Backend 在复杂中间件顺序、循环依赖绕过、测试分层原则等高认知负担位置写块注释,示例:
|
||||||
|
- `backend/packages/harness/deerflow/agents/lead_agent/agent.py`(middleware 顺序约束)
|
||||||
|
- `backend/tests/conftest.py`(循环导入链与 mock 注入原因)
|
||||||
|
- `backend/tests/test_client_e2e.py`(测试金字塔与运行边界)
|
||||||
|
|
||||||
|
**JSDoc/TSDoc:**
|
||||||
|
- Frontend 在共享工具函数处使用 JSDoc 解释行为与边界(`frontend/src/lib/utils.ts`)。
|
||||||
|
- Backend 在公共类/函数上常见 docstring,测试文件顶部也有职责说明。
|
||||||
|
|
||||||
|
## Function Design
|
||||||
|
|
||||||
|
**Size:** 无硬性行数限制;允许长函数,但通过“局部 helper + 注释分段”提高可读性(见 `backend/packages/harness/deerflow/client.py`)。
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- 偏向显式关键字参数与默认值,Python 常见 `*` 强制关键字调用(`DeerFlowClient.__init__`)。
|
||||||
|
- 测试 helper 参数常封装为对象/字典,减少调用点重复(`frontend/tests/e2e/support/chat-helpers.ts`)。
|
||||||
|
|
||||||
|
**Return Values:**
|
||||||
|
- Python 公开接口通常返回结构化对象或强类型(如 `StreamEvent` dataclass in `backend/packages/harness/deerflow/client.py`)。
|
||||||
|
- Frontend helper 对异常场景返回 `null/undefined` 并由调用方判定(`frontend/src/core/uploads/prompt-input-files.test.mjs` 覆盖该行为)。
|
||||||
|
|
||||||
|
## Module Design
|
||||||
|
|
||||||
|
**Exports:**
|
||||||
|
- Python 模块多为显式函数/类导出,避免通配导入;测试按模块行为组织断言。
|
||||||
|
- Frontend 使用 `export function` / `export const` 的命名导出为主(`frontend/src/lib/utils.ts`)。
|
||||||
|
|
||||||
|
**Barrel Files:**
|
||||||
|
- 后端包存在少量 `__init__.py` 聚合导出(如 `backend/packages/harness/deerflow/models/__init__.py`)。
|
||||||
|
- Frontend 未形成统一 barrel 规范;新增公共模块应优先“就近导出 + 明确 import 路径”,避免深层 barrel 隐式耦合。
|
||||||
|
|
||||||
|
## CI / 质量门禁约定
|
||||||
|
|
||||||
|
- CI 工作流定义于 `.github/workflows/lint-check.yml`、`.github/workflows/backend-unit-tests.yml`。
|
||||||
|
- 合入前最低门禁:
|
||||||
|
- Backend: `make lint`(ruff check + format --check)
|
||||||
|
- Frontend: `pnpm format`、`pnpm lint`、`pnpm typecheck`、`pnpm build`
|
||||||
|
- Backend 单测:`make test`(pytest)
|
||||||
|
- Frontend E2E 未纳入默认 CI 工作流;仅定义本地命令 `pnpm test:e2e`(`frontend/package.json`)。
|
||||||
|
|
||||||
|
## 简短结论
|
||||||
|
|
||||||
|
- 本仓库已形成“双栈分治”质量约定:Backend 以 `ruff + pytest` 为核心,Frontend 以 `eslint + prettier + typecheck + build` 为核心,并在 CI 中执行。
|
||||||
|
- 后续新增代码应严格沿用现有命名、导入分组与异常处理风格;新增测试优先补齐 Frontend 单元测试执行入口与 E2E 的 CI 接入,避免“有测试文件但无持续校验”。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Convention analysis: 2026-04-07*
|
||||||
|
|
@ -0,0 +1,168 @@
|
||||||
|
# 外部集成审计(Tech Focus)
|
||||||
|
|
||||||
|
**分析日期:** 2026-04-07
|
||||||
|
|
||||||
|
## APIs 与外部服务
|
||||||
|
|
||||||
|
**LLM Provider(通过配置动态切换):**
|
||||||
|
- OpenAI / Anthropic / Gemini / DeepSeek / MiniMax / OpenRouter(示例在 `config.example.yaml` 的 `models`)
|
||||||
|
- SDK/适配层:`langchain_openai`、`langchain_anthropic`、`langchain_google_genai`、`langchain_deepseek`(`backend/packages/harness/pyproject.toml`)
|
||||||
|
- 认证:`config.yaml` 中模型字段支持 `$ENV_VAR` 注入(`backend/packages/harness/deerflow/config/app_config.py`)
|
||||||
|
|
||||||
|
**MCP(Model Context Protocol)服务:**
|
||||||
|
- 支持 `stdio` / `sse` / `http` 三种传输(`backend/packages/harness/deerflow/mcp/client.py`)
|
||||||
|
- 管理接口:`GET/PUT /api/mcp/config`(`backend/app/gateway/routers/mcp.py`)
|
||||||
|
- 配置文件:`extensions_config.json`(`backend/packages/harness/deerflow/config/extensions_config.py`)
|
||||||
|
- OAuth:HTTP/SSE MCP 可启用 token 自动刷新(`backend/packages/harness/deerflow/mcp/oauth.py`)
|
||||||
|
|
||||||
|
**Web 搜索与抓取:**
|
||||||
|
- DuckDuckGo(`ddgs`,免 key):`backend/packages/harness/deerflow/community/ddg_search/tools.py`
|
||||||
|
- Jina Reader:`https://r.jina.ai/`(可选 `JINA_API_KEY`,`backend/packages/harness/deerflow/community/jina_ai/jina_client.py`)
|
||||||
|
- Tavily(可配置 api_key):`backend/packages/harness/deerflow/community/tavily/tools.py`
|
||||||
|
- Firecrawl(可配置 api_key):`backend/packages/harness/deerflow/community/firecrawl/tools.py`
|
||||||
|
- InfoQuest(`INFOQUEST_API_KEY`):`backend/packages/harness/deerflow/community/infoquest/infoquest_client.py`
|
||||||
|
|
||||||
|
**IM 渠道:**
|
||||||
|
- Feishu/Lark、Slack、Telegram、WeCom(`backend/app/channels/*.py`)
|
||||||
|
- Feishu:`app_id`/`app_secret`
|
||||||
|
- Slack:`bot_token`/`app_token`
|
||||||
|
- Telegram:`bot_token`
|
||||||
|
- WeCom:`bot_id`/`bot_secret`
|
||||||
|
|
||||||
|
**前端到后端接口:**
|
||||||
|
- 前端直接调用网关 REST:`/api/models`、`/api/memory`、`/api/skills`、`/api/mcp/config`、`/api/threads/*/uploads`(`frontend/src/core/*/api.ts`)
|
||||||
|
- 前端通过 `@langchain/langgraph-sdk` 调用 LangGraph API(`frontend/src/core/api/api-client.ts`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 集成模式以“配置驱动 + 适配层解耦”为主;新增三方服务优先走 `config.yaml` / `extensions_config.json`,避免硬编码。
|
||||||
|
|
||||||
|
## 数据存储
|
||||||
|
|
||||||
|
**会话状态与持久化:**
|
||||||
|
- Checkpointer 支持:`memory` / `sqlite` / `postgres`(`backend/packages/harness/deerflow/config/checkpointer_config.py`)
|
||||||
|
- 默认示例为 SQLite(`config.example.yaml` 的 `checkpointer` 段)
|
||||||
|
- 同步 Store 与 checkpointer 类型保持一致(`backend/packages/harness/deerflow/runtime/store/provider.py`)
|
||||||
|
|
||||||
|
**文件与工件存储:**
|
||||||
|
- 上传与工件基于本地文件系统路径(`backend/app/gateway/routers/uploads.py`、`backend/app/gateway/routers/artifacts.py`、`backend/packages/harness/deerflow/uploads/manager.py`)
|
||||||
|
|
||||||
|
**缓存:**
|
||||||
|
- 未检测到 Redis/Memcached 等独立缓存服务;主要使用进程内缓存/单例(如配置缓存与客户端缓存,见 `backend/packages/harness/deerflow/config/*.py`、`frontend/src/core/api/api-client.ts`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 当前默认可单机落地(SQLite + 本地文件);若进入多实例部署,应优先切换 Postgres checkpointer/store 并外置文件存储策略。
|
||||||
|
|
||||||
|
## 身份认证与权限
|
||||||
|
|
||||||
|
**前端身份认证:**
|
||||||
|
- `better-auth`(`frontend/src/server/better-auth/config.ts`、`frontend/src/app/api/auth/[...all]/route.ts`)
|
||||||
|
- 当前配置启用 `emailAndPassword`,GitHub 相关变量为可选(`frontend/src/env.js`)
|
||||||
|
|
||||||
|
**MCP 授权:**
|
||||||
|
- MCP HTTP/SSE OAuth 支持 `client_credentials` 与 `refresh_token`(`backend/packages/harness/deerflow/mcp/oauth.py`)
|
||||||
|
- 可针对每个 MCP server 配置 headers/env/oauth(`backend/packages/harness/deerflow/config/extensions_config.py`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 认证面分为“前端会话认证”和“后端集成凭证认证”两条线;规划时应分离处理,避免混用同一密钥域。
|
||||||
|
|
||||||
|
## 观测与可观测性
|
||||||
|
|
||||||
|
**Tracing:**
|
||||||
|
- LangSmith(`LANGSMITH_*` / `LANGCHAIN_*`)与 Langfuse(`LANGFUSE_*`)双支持(`backend/packages/harness/deerflow/config/tracing_config.py`)
|
||||||
|
- 回调挂载在模型创建阶段(`backend/packages/harness/deerflow/tracing/factory.py`、`backend/packages/harness/deerflow/models/factory.py`)
|
||||||
|
|
||||||
|
**日志:**
|
||||||
|
- Gateway 使用 Python logging,支持 `LOG_LEVEL`(`backend/app/gateway/app.py`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- Tracing 已具备按环境开关能力,建议在 staging 强制开启至少一个 provider,减少线上问题追踪成本。
|
||||||
|
|
||||||
|
## CI/CD 与部署集成
|
||||||
|
|
||||||
|
**CI:**
|
||||||
|
- GitHub Actions:
|
||||||
|
- 后端单测(`.github/workflows/backend-unit-tests.yml`)
|
||||||
|
- 前后端 lint/type/build(`.github/workflows/lint-check.yml`)
|
||||||
|
|
||||||
|
**部署:**
|
||||||
|
- 一体化入口:`make dev` / `make up`(根 `Makefile`)
|
||||||
|
- Nginx 统一反代前端 + LangGraph + Gateway(`backend/README.md`、`docker/nginx/nginx.local.conf`、`docker/nginx/nginx.conf`)
|
||||||
|
- Docker 编排文件存在:`docker/docker-compose.yaml`、`docker/docker-compose-dev.yaml`
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 已形成本地开发与容器部署双通道;下一步提升点是把 e2e(Playwright)纳入 CI 的默认门禁。
|
||||||
|
|
||||||
|
## 环境变量(关键清单)
|
||||||
|
|
||||||
|
**前端(`frontend/src/env.js`):**
|
||||||
|
- `BETTER_AUTH_SECRET`
|
||||||
|
- `BETTER_AUTH_GITHUB_CLIENT_ID`
|
||||||
|
- `BETTER_AUTH_GITHUB_CLIENT_SECRET`
|
||||||
|
- `GITHUB_OAUTH_TOKEN`
|
||||||
|
- `NEXT_PUBLIC_BACKEND_BASE_URL`
|
||||||
|
- `NEXT_PUBLIC_LANGGRAPH_BASE_URL`
|
||||||
|
- `NEXT_PUBLIC_STATIC_WEBSITE_ONLY`
|
||||||
|
- `SKIP_ENV_VALIDATION`
|
||||||
|
|
||||||
|
**后端网关(`backend/app/gateway/config.py`、`backend/app/gateway/app.py`):**
|
||||||
|
- `GATEWAY_HOST`
|
||||||
|
- `GATEWAY_PORT`
|
||||||
|
- `CORS_ORIGINS`
|
||||||
|
- `SKILL_CONTENT_API_URL`
|
||||||
|
- `LOG_LEVEL`
|
||||||
|
|
||||||
|
**后端主配置解析(`backend/packages/harness/deerflow/config/app_config.py`):**
|
||||||
|
- `DEER_FLOW_CONFIG_PATH`
|
||||||
|
- `DEER_FLOW_EXTENSIONS_CONFIG_PATH`
|
||||||
|
- 以及 `config.yaml` / `extensions_config.json` 中所有 `$VAR` 占位符
|
||||||
|
|
||||||
|
**Tracing(`backend/packages/harness/deerflow/config/tracing_config.py`):**
|
||||||
|
- `LANGSMITH_TRACING` / `LANGCHAIN_TRACING_V2` / `LANGCHAIN_TRACING`
|
||||||
|
- `LANGSMITH_API_KEY` / `LANGCHAIN_API_KEY`
|
||||||
|
- `LANGSMITH_PROJECT` / `LANGCHAIN_PROJECT`
|
||||||
|
- `LANGSMITH_ENDPOINT` / `LANGCHAIN_ENDPOINT`
|
||||||
|
- `LANGFUSE_TRACING`
|
||||||
|
- `LANGFUSE_PUBLIC_KEY`
|
||||||
|
- `LANGFUSE_SECRET_KEY`
|
||||||
|
- `LANGFUSE_BASE_URL`
|
||||||
|
|
||||||
|
**Channels(`config.example.yaml`、`backend/app/channels/service.py`):**
|
||||||
|
- `FEISHU_APP_ID`、`FEISHU_APP_SECRET`
|
||||||
|
- `SLACK_BOT_TOKEN`、`SLACK_APP_TOKEN`
|
||||||
|
- `TELEGRAM_BOT_TOKEN`
|
||||||
|
- `WECOM_BOT_ID`、`WECOM_BOT_SECRET`
|
||||||
|
- `DEER_FLOW_CHANNELS_LANGGRAPH_URL`
|
||||||
|
- `DEER_FLOW_CHANNELS_GATEWAY_URL`
|
||||||
|
|
||||||
|
**社区工具与凭证:**
|
||||||
|
- `JINA_API_KEY`(`backend/packages/harness/deerflow/community/jina_ai/jina_client.py`)
|
||||||
|
- `INFOQUEST_API_KEY`(`backend/packages/harness/deerflow/community/infoquest/infoquest_client.py`)
|
||||||
|
- Claude/Codex 凭证相关变量(`backend/packages/harness/deerflow/models/credential_loader.py`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 环境变量来源分散于前端 env schema、后端配置加载器和工具客户端;后续应维护一份单独的“env contract”用于部署校验。
|
||||||
|
|
||||||
|
## Webhook 与回调
|
||||||
|
|
||||||
|
**Incoming:**
|
||||||
|
- 未检测到典型公网 webhook 接收实现;IM 渠道主要是 WebSocket/轮询主动连接(`backend/app/channels/*.py`)
|
||||||
|
|
||||||
|
**Outgoing:**
|
||||||
|
- MCP OAuth token endpoint(按 server 配置动态请求,`backend/packages/harness/deerflow/mcp/oauth.py`)
|
||||||
|
- 远端技能内容拉取接口(`SKILL_CONTENT_API_URL`,`backend/app/gateway/config.py`)
|
||||||
|
- 第三方搜索/抓取 API(Jina、InfoQuest、Tavily、Firecrawl)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 当前外部交互以“主动调用”为主,公网暴露面较小;若新增 webhook,应同步补充签名校验与重放保护。
|
||||||
|
|
||||||
|
## 总结(规划导向)
|
||||||
|
|
||||||
|
- DeerFlow 当前集成体系已经具备“多模型 + 多工具 + 多渠道 + 可选追踪”的完整闭环,且关键接入点均配置化。
|
||||||
|
- 后续规划优先级建议:
|
||||||
|
1. 统一环境变量契约与部署校验(降低配置错误率)
|
||||||
|
2. 多实例场景的持久化与文件存储升级(Postgres + 外置对象存储)
|
||||||
|
3. 外部集成回归套件(MCP OAuth、IM 渠道、搜索工具)持续化到 CI
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*集成审计完成于 2026-04-07(基于 `backend`、`frontend`、`config.example.yaml`、CI 工作流与网关/工具实现静态审计)*
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
# 技术栈(Tech Focus)
|
||||||
|
|
||||||
|
**分析日期:** 2026-04-07
|
||||||
|
|
||||||
|
## 语言
|
||||||
|
|
||||||
|
**主语言:**
|
||||||
|
- Python 3.12+:后端网关、Agent Runtime、MCP/工具系统(`backend/pyproject.toml`、`backend/.python-version`、`backend/langgraph.json`、`backend/packages/harness/pyproject.toml`)
|
||||||
|
- TypeScript(ES2022):前端 App Router、API 代理、状态管理与 UI 组件(`frontend/package.json`、`frontend/tsconfig.json`)
|
||||||
|
|
||||||
|
**次要语言:**
|
||||||
|
- JavaScript(ESM):Next.js/工具链配置(`frontend/next.config.js`、`frontend/eslint.config.js`、`frontend/prettier.config.js`)
|
||||||
|
- YAML:运行时模型与工具编排配置(`config.example.yaml`、`config.yaml`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 代码库是 Python + TypeScript 双栈,后端偏 AI runtime 编排,前端偏 Next.js 应用层;版本锚点明确(Python 3.12、Node 22)。
|
||||||
|
|
||||||
|
## 运行时
|
||||||
|
|
||||||
|
**后端运行时:**
|
||||||
|
- Python 3.12(`backend/.python-version`、`backend/langgraph.json`)
|
||||||
|
- FastAPI + Uvicorn(`backend/pyproject.toml`、`backend/Makefile`)
|
||||||
|
- LangGraph Server(`backend/Makefile` 的 `uv run langgraph dev`)
|
||||||
|
|
||||||
|
**前端运行时:**
|
||||||
|
- Node.js 22+(`frontend/README.md`;CI 也固定 Node 22,见 `.github/workflows/lint-check.yml`)
|
||||||
|
- Next.js 16 + React 19(`frontend/package.json`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 运行时依赖在文档与 CI 双重约束,团队应以 Python 3.12 + Node 22 作为本地/CI 基线。
|
||||||
|
|
||||||
|
## 依赖与包管理
|
||||||
|
|
||||||
|
**后端:**
|
||||||
|
- 包管理器:`uv`(`Makefile`、`backend/Makefile`)
|
||||||
|
- 工作区:`backend` 主工程 + `backend/packages/harness`(`backend/pyproject.toml` 的 `[tool.uv.workspace]`)
|
||||||
|
- 锁文件:`backend/uv.lock`(存在)
|
||||||
|
|
||||||
|
**前端:**
|
||||||
|
- 包管理器:`pnpm@10.26.2`(`frontend/package.json`)
|
||||||
|
- 锁文件:`frontend/pnpm-lock.yaml`(存在)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 后端与前端均已锁版本;规划阶段应坚持 `uv sync` + `pnpm install --frozen-lockfile`,避免跨环境漂移。
|
||||||
|
|
||||||
|
## 核心框架
|
||||||
|
|
||||||
|
**后端核心:**
|
||||||
|
- `langgraph` / `langgraph-api`:Agent 图运行与 API 能力(`backend/packages/harness/pyproject.toml`)
|
||||||
|
- `langchain` 生态:模型适配、工具接口、回调(`backend/packages/harness/pyproject.toml`、`backend/packages/harness/deerflow/models/factory.py`)
|
||||||
|
- `fastapi` + `sse-starlette`:网关 REST 与流式接口(`backend/pyproject.toml`、`backend/app/gateway/routers/runs.py`)
|
||||||
|
|
||||||
|
**前端核心:**
|
||||||
|
- `next` 16(App Router)+ `react` 19(`frontend/package.json`)
|
||||||
|
- `@tanstack/react-query`:前端数据获取与缓存(`frontend/src/core/*/hooks.ts`)
|
||||||
|
- `@langchain/langgraph-sdk`:前端直连 LangGraph API(`frontend/src/core/api/api-client.ts`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 架构重心是 LangGraph runtime + FastAPI gateway + Next.js UI 三段式,新增能力应优先挂靠这三层边界。
|
||||||
|
|
||||||
|
## 构建与开发工具
|
||||||
|
|
||||||
|
**后端:**
|
||||||
|
- 启动:`uv run langgraph dev`、`uv run uvicorn ...`(`backend/Makefile`)
|
||||||
|
- 测试:`pytest`(`backend/pyproject.toml`、`backend/Makefile`)
|
||||||
|
- 质量:`ruff`(`backend/ruff.toml`)
|
||||||
|
|
||||||
|
**前端:**
|
||||||
|
- 开发:`next dev --turbo`(`frontend/package.json`)
|
||||||
|
- 构建:`next build`(`frontend/package.json`)
|
||||||
|
- 质量:`eslint` + `typescript-eslint` + `prettier`(`frontend/eslint.config.js`、`frontend/prettier.config.js`)
|
||||||
|
- E2E:`playwright`(`frontend/playwright.config.ts`)
|
||||||
|
|
||||||
|
**CI:**
|
||||||
|
- GitHub Actions:后端单测、前后端 lint/type/build(`.github/workflows/backend-unit-tests.yml`、`.github/workflows/lint-check.yml`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 工具链完整,且 CI 已覆盖“格式/Lint/类型/构建/后端单测”;后续 phase 应直接复用现有流水线,不建议新建并行脚本体系。
|
||||||
|
|
||||||
|
## 关键依赖(对规划最有影响)
|
||||||
|
|
||||||
|
**AI 与模型:**
|
||||||
|
- `langchain-openai`、`langchain-anthropic`、`langchain-google-genai`、`langchain-deepseek`(`backend/packages/harness/pyproject.toml`)
|
||||||
|
- `langgraph-sdk`(前后端均使用,`backend/pyproject.toml`、`frontend/package.json`)
|
||||||
|
|
||||||
|
**集成与工具:**
|
||||||
|
- `langchain-mcp-adapters`(MCP 多服务接入,`backend/packages/harness/pyproject.toml`)
|
||||||
|
- `slack-sdk`、`python-telegram-bot`、`lark-oapi`、`wecom-aibot-python-sdk`(`backend/pyproject.toml`、`backend/app/channels/*.py`)
|
||||||
|
- `tavily-python`、`firecrawl-py`、`ddgs`、`duckdb`(`backend/packages/harness/pyproject.toml`)
|
||||||
|
|
||||||
|
**前端平台能力:**
|
||||||
|
- `better-auth`(鉴权,`frontend/src/server/better-auth/config.ts`)
|
||||||
|
- `@t3-oss/env-nextjs` + `zod`(环境变量校验,`frontend/src/env.js`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 依赖风险主要在第三方模型/搜索/IM SDK 的 API 兼容性;规划中应为这些“边缘适配层”预留回归验证。
|
||||||
|
|
||||||
|
## 配置体系
|
||||||
|
|
||||||
|
**应用配置:**
|
||||||
|
- 主配置:`config.yaml`(示例:`config.example.yaml`),支持 `$ENV_VAR` 解析(`backend/packages/harness/deerflow/config/app_config.py`)
|
||||||
|
- 扩展配置:`extensions_config.json`(MCP servers + skills 状态,`backend/packages/harness/deerflow/config/extensions_config.py`)
|
||||||
|
|
||||||
|
**前端配置:**
|
||||||
|
- 运行时环境校验:`frontend/src/env.js`
|
||||||
|
- 前端 API 基址解析:`frontend/src/core/config/index.ts`
|
||||||
|
|
||||||
|
**敏感配置文件存在性(仅记录存在,不读取值):**
|
||||||
|
- 根目录 `.env`
|
||||||
|
- 前端 `frontend/.env`、`frontend/.env.example`
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 配置源分层清晰(主业务配置 + 扩展配置 + 前端 env);新功能应优先扩展现有配置模型,不要散落新增私有配置文件。
|
||||||
|
|
||||||
|
## 平台与部署要求
|
||||||
|
|
||||||
|
**开发:**
|
||||||
|
- `make install` 安装前后端依赖(`Makefile`)
|
||||||
|
- `make dev` 一键启动(LangGraph + Gateway + Frontend + Nginx,见 `Makefile` 和 `backend/README.md`)
|
||||||
|
|
||||||
|
**生产/容器:**
|
||||||
|
- 前端 `next.config.js` 使用 `output: "standalone"`(`frontend/next.config.js`)
|
||||||
|
- 支持 Docker 部署脚本与编排目录(`docker/docker-compose.yaml`、`docker/docker-compose-dev.yaml`、`scripts/deploy.sh`、`scripts/docker.sh`)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
- 默认目标是容器化/反向代理下的整套部署;后续规划应把“网关端口与反代路径一致性”作为上线前强校验项。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*栈分析完成于 2026-04-07(基于 `backend`、`frontend`、根目录构建脚本与配置文件的静态审计)*
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
# 代码库结构
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-07
|
||||||
|
|
||||||
|
## 目录布局
|
||||||
|
|
||||||
|
```text
|
||||||
|
deerflow2/
|
||||||
|
├── backend/ # Python 后端(Gateway + Harness workspace)
|
||||||
|
│ ├── app/ # 应用壳层:HTTP Gateway、IM channels
|
||||||
|
│ ├── packages/harness/deerflow/ # 运行时内核:agent/runtime/tools/sandbox
|
||||||
|
│ ├── tests/ # 后端测试
|
||||||
|
│ └── pyproject.toml # 后端 workspace 定义
|
||||||
|
├── frontend/ # Next.js 前端(App Router)
|
||||||
|
│ ├── src/app/ # 页面与路由入口
|
||||||
|
│ ├── src/components/ # UI 与业务组件
|
||||||
|
│ ├── src/core/ # 领域能力层(API/hooks/types)
|
||||||
|
│ ├── src/server/ # 服务端能力(auth)
|
||||||
|
│ └── tests/ # 前端 E2E 测试
|
||||||
|
├── docker/ # 部署与网关编排
|
||||||
|
├── docs/ # 项目文档
|
||||||
|
├── scripts/ # 开发与部署脚本
|
||||||
|
└── skills/ # 技能资源(public skills)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 目录职责
|
||||||
|
|
||||||
|
**`backend/app`:**
|
||||||
|
- Purpose: 面向产品的 API/协议层,不承载核心 agent 组装逻辑
|
||||||
|
- Contains: `gateway/app.py`、`gateway/routers/*.py`、`channels/*.py`
|
||||||
|
- Key files: `backend/app/gateway/app.py`, `backend/app/gateway/services.py`, `backend/app/channels/service.py`
|
||||||
|
|
||||||
|
**`backend/packages/harness/deerflow`:**
|
||||||
|
- Purpose: 可复用内核层,封装智能体运行时与能力模块
|
||||||
|
- Contains: `agents/`, `runtime/`, `tools/`, `sandbox/`, `skills/`, `models/`, `config/`
|
||||||
|
- Key files: `backend/packages/harness/deerflow/agents/lead_agent/agent.py`, `backend/packages/harness/deerflow/runtime/runs/manager.py`, `backend/packages/harness/deerflow/runtime/stream_bridge/memory.py`
|
||||||
|
|
||||||
|
**`frontend/src/app`:**
|
||||||
|
- Purpose: Next.js 路由与页面入口,组合 UI 与 core 能力
|
||||||
|
- Contains: 根布局、workspace 页面、docs 页面、API route handlers
|
||||||
|
- Key files: `frontend/src/app/layout.tsx`, `frontend/src/app/workspace/layout.tsx`, `frontend/src/app/workspace/chats/[thread_id]/page.tsx`
|
||||||
|
|
||||||
|
**`frontend/src/components`:**
|
||||||
|
- Purpose: 可复用 UI 组件与工作台业务组件
|
||||||
|
- Contains: `ui/*`, `workspace/*`, `landing/*`, `ai-elements/*`
|
||||||
|
- Key files: `frontend/src/components/workspace/workspace-container.tsx`, `frontend/src/components/workspace/chats/use-thread-chat.ts`
|
||||||
|
|
||||||
|
**`frontend/src/core`:**
|
||||||
|
- Purpose: 前端领域逻辑层,统一管理数据访问、hook 与类型
|
||||||
|
- Contains: `threads/`, `api/`, `memory/`, `models/`, `skills/`, `uploads/`, `settings/`
|
||||||
|
- Key files: `frontend/src/core/threads/hooks.ts`, `frontend/src/core/api/api-client.ts`, `frontend/src/core/config/index.ts`
|
||||||
|
|
||||||
|
## 关键文件位置
|
||||||
|
|
||||||
|
**Entry Points:**
|
||||||
|
- `backend/app/gateway/app.py`: FastAPI 入口与路由总装
|
||||||
|
- `frontend/src/app/layout.tsx`: 前端根布局入口
|
||||||
|
- `frontend/src/app/page.tsx`: Landing 页面入口
|
||||||
|
- `frontend/src/app/workspace/page.tsx`: 工作台入口重定向
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
- `backend/pyproject.toml`: Python 依赖与 workspace
|
||||||
|
- `frontend/package.json`: 前端依赖与脚本
|
||||||
|
- `frontend/tsconfig.json`: TS 编译策略与 `@/*` 别名
|
||||||
|
- `frontend/next.config.js`: Next 构建输出与运行参数
|
||||||
|
- `config.yaml`: 运行配置主文件(存在,勿在规划文档中记录敏感值)
|
||||||
|
|
||||||
|
**Core Logic:**
|
||||||
|
- `backend/app/gateway/services.py`: run 生命周期业务逻辑与 SSE 格式化
|
||||||
|
- `backend/app/gateway/routers/thread_runs.py`: 线程 run 协议接口
|
||||||
|
- `backend/packages/harness/deerflow/agents/lead_agent/agent.py`: 主 Agent 构建逻辑
|
||||||
|
- `backend/packages/harness/deerflow/runtime/runs/manager.py`: run 状态机与并发控制
|
||||||
|
- `frontend/src/core/threads/hooks.ts`: 流式会话、线程列表、突变逻辑
|
||||||
|
- `frontend/src/core/api/api-client.ts`: LangGraph SDK 客户端封装
|
||||||
|
|
||||||
|
**Testing:**
|
||||||
|
- `backend/tests/*.py`: 后端单元/集成测试
|
||||||
|
- `frontend/tests/e2e/*`: 前端端到端测试(Playwright)
|
||||||
|
- `frontend/src/core/**/*.{test.ts,test.mjs}`: 前端核心逻辑单测
|
||||||
|
|
||||||
|
## 命名约定
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- 前端组件文件:`kebab-case.tsx`(示例:`workspace-container.tsx`)
|
||||||
|
- 前端 Hook 文件:`use-*.ts` 或 `hooks.ts`(示例:`use-thread-chat.ts`, `threads/hooks.ts`)
|
||||||
|
- 后端 Python 文件:`snake_case.py`(示例:`thread_runs.py`, `memory_middleware.py`)
|
||||||
|
- 路由文件:按资源名命名(示例:`routers/threads.py`, `routers/models.py`)
|
||||||
|
|
||||||
|
**Directories:**
|
||||||
|
- 前端按职责分层:`app`(路由)/`components`(视图)/`core`(领域)
|
||||||
|
- 后端按边界分层:`app`(应用层)/`packages/harness/deerflow`(内核层)
|
||||||
|
|
||||||
|
## 新增代码放置规则(可执行)
|
||||||
|
|
||||||
|
**新增后端 API 端点:**
|
||||||
|
- 路由定义: `backend/app/gateway/routers/{resource}.py`
|
||||||
|
- 复用业务逻辑: 优先放 `backend/app/gateway/services.py` 或同级 `{resource}_service.py`
|
||||||
|
- 依赖获取: 统一通过 `backend/app/gateway/deps.py`
|
||||||
|
|
||||||
|
**新增 Agent/运行时能力:**
|
||||||
|
- Agent 相关: `backend/packages/harness/deerflow/agents/*`
|
||||||
|
- 运行时状态/流: `backend/packages/harness/deerflow/runtime/*`
|
||||||
|
- 工具能力: `backend/packages/harness/deerflow/tools/*` 或 `community/*`
|
||||||
|
- 规则: 不在 `backend/app/*` 写核心算法/agent 编排逻辑
|
||||||
|
|
||||||
|
**新增前端业务功能:**
|
||||||
|
- 页面入口: `frontend/src/app/{route}/page.tsx`
|
||||||
|
- 业务组件: `frontend/src/components/workspace/*`(工作台)或对应域目录
|
||||||
|
- 数据访问与副作用: `frontend/src/core/{domain}/api.ts|hooks.ts|types.ts`
|
||||||
|
- 规则: 页面层只做组合,不直接实现复杂 API 调用细节
|
||||||
|
|
||||||
|
**新增 Next API 代理:**
|
||||||
|
- 放置于 `frontend/src/app/api/{resource}/route.ts` 或 `[...path]/route.ts`
|
||||||
|
- 代理逻辑复用现有 `proxyRequest` 模式(参考 `frontend/src/app/api/memory/[...path]/route.ts`)
|
||||||
|
|
||||||
|
**新增测试:**
|
||||||
|
- 后端: `backend/tests/test_{feature}.py`
|
||||||
|
- 前端 core 单测: 与实现文件同目录 `*.test.ts|*.test.mjs`
|
||||||
|
- 前端 E2E: `frontend/tests/e2e/{feature}.spec.ts`
|
||||||
|
|
||||||
|
## 特殊目录说明
|
||||||
|
|
||||||
|
**`backend/src`:**
|
||||||
|
- Purpose: 旧路径兼容目录(当前主要为 `__pycache__`)
|
||||||
|
- Generated: Yes(当前内容以缓存文件为主)
|
||||||
|
- Committed: Yes(目录存在于仓库)
|
||||||
|
- Guidance: 新代码不要放在 `backend/src`,统一落到 `backend/packages/harness/deerflow` 或 `backend/app`
|
||||||
|
|
||||||
|
**`frontend/.next` 与 `frontend/node_modules`:**
|
||||||
|
- Purpose: 构建产物与依赖缓存
|
||||||
|
- Generated: Yes
|
||||||
|
- Committed: No(应视为构建输出)
|
||||||
|
|
||||||
|
**`.planning/codebase`:**
|
||||||
|
- Purpose: 供后续规划/执行代理读取的代码库认知文档
|
||||||
|
- Generated: Yes(由 map 阶段生成)
|
||||||
|
- Committed: Yes(作为流程资产)
|
||||||
|
|
||||||
|
**结论:**
|
||||||
|
该仓库最重要的结构约束是“后端 Harness 与 App 分层 + 前端 app/components/core 三段分层”。后续新增功能应优先沿既有目录职责扩展,避免把核心逻辑散落到路由层或页面层。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Structure analysis: 2026-04-07*
|
||||||
|
|
@ -0,0 +1,206 @@
|
||||||
|
# Testing Patterns
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-07
|
||||||
|
|
||||||
|
## Test Framework
|
||||||
|
|
||||||
|
**Runner:**
|
||||||
|
- Backend: `pytest` (>=8.0.0, 定义于 `backend/pyproject.toml`)
|
||||||
|
- Frontend E2E: `@playwright/test` (定义于 `frontend/package.json`)
|
||||||
|
- Frontend 轻量单测: Node 内置 `node:test` + `node:assert/strict`(示例见 `frontend/src/core/api/stream-mode.test.ts`)
|
||||||
|
- Config: `frontend/playwright.config.ts`(E2E);Backend 未检测到独立 `pytest.ini`/`tox.ini`
|
||||||
|
|
||||||
|
**Assertion Library:**
|
||||||
|
- Backend: `pytest` 原生断言
|
||||||
|
- Frontend E2E: Playwright `expect`
|
||||||
|
- Frontend 轻量单测: `node:assert/strict`
|
||||||
|
|
||||||
|
**Run Commands:**
|
||||||
|
```bash
|
||||||
|
cd backend && make test # 运行后端测试(pytest tests/ -v)
|
||||||
|
cd backend && make lint # 后端静态检查(ruff check + format --check)
|
||||||
|
cd frontend && pnpm test:e2e # 运行 Playwright E2E
|
||||||
|
cd frontend && pnpm test:e2e:ui # Playwright UI 模式
|
||||||
|
cd frontend && pnpm lint && pnpm typecheck # 前端质量门禁
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test File Organization
|
||||||
|
|
||||||
|
**Location:**
|
||||||
|
- Backend 测试集中在 `backend/tests/`,按模块与能力拆分(如 `test_client.py`、`test_stream_bridge.py`)。
|
||||||
|
- Frontend E2E 在 `frontend/tests/e2e/`,辅助函数在 `frontend/tests/e2e/support/`。
|
||||||
|
- Frontend 轻量模块测试与实现同目录共置(如 `frontend/src/core/uploads/*.test.mjs`)。
|
||||||
|
|
||||||
|
**Naming:**
|
||||||
|
- Python: `test_*.py`
|
||||||
|
- Playwright: `*.spec.ts`
|
||||||
|
- Node 内置测试: `*.test.ts` / `*.test.mjs`
|
||||||
|
|
||||||
|
**Structure:**
|
||||||
|
```text
|
||||||
|
backend/tests/test_*.py
|
||||||
|
frontend/tests/e2e/*.spec.ts
|
||||||
|
frontend/tests/e2e/support/*.ts
|
||||||
|
frontend/src/**/**.test.ts
|
||||||
|
frontend/src/**/**.test.mjs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Structure
|
||||||
|
|
||||||
|
**Suite Organization:**
|
||||||
|
```python
|
||||||
|
# backend/tests/test_stream_bridge.py
|
||||||
|
@pytest.fixture
|
||||||
|
def bridge() -> MemoryStreamBridge:
|
||||||
|
return MemoryStreamBridge(queue_maxsize=256)
|
||||||
|
|
||||||
|
@pytest.mark.anyio
|
||||||
|
async def test_publish_subscribe(bridge: MemoryStreamBridge):
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// frontend/tests/e2e/input-and-compose.spec.ts
|
||||||
|
test.describe("聊天工作台 / 输入区与发送", () => {
|
||||||
|
test("DF-INPUT-001 ...", async ({ page }, testInfo) => {
|
||||||
|
...
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Patterns:**
|
||||||
|
- Setup pattern:
|
||||||
|
- Backend 使用 `conftest.py` 全局 fixture 与 import/mock 预处理(`backend/tests/conftest.py`)。
|
||||||
|
- E2E 使用 `chat-helpers.ts` 封装 URL 构建、页面打开、发送消息、线程前置校验。
|
||||||
|
- Teardown pattern:
|
||||||
|
- Backend 通过 `tmp_path` + `monkeypatch` 隔离文件系统与全局单例(`backend/tests/test_client_e2e.py`)。
|
||||||
|
- Frontend Node 测试手动还原 `globalThis.fetch`/`console.warn`。
|
||||||
|
- Assertion pattern:
|
||||||
|
- Backend 侧重行为与事件序列断言(含异常、边界、并发)。
|
||||||
|
- E2E 使用 `expect.poll` 与语义选择器(`getByTestId`、`getByRole`)减少时序抖动。
|
||||||
|
|
||||||
|
## Mocking
|
||||||
|
|
||||||
|
**Framework:** `unittest.mock` + `pytest.monkeypatch`(Backend);函数级覆写全局对象(Frontend Node tests)
|
||||||
|
|
||||||
|
**Patterns:**
|
||||||
|
```python
|
||||||
|
# backend/tests/test_model_factory.py
|
||||||
|
def _patch_factory(monkeypatch, app_config, model_class=FakeChatModel):
|
||||||
|
monkeypatch.setattr(factory_module, "get_app_config", lambda: app_config)
|
||||||
|
monkeypatch.setattr(factory_module, "resolve_class", lambda path, base: model_class)
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// frontend/src/core/uploads/prompt-input-files.test.mjs
|
||||||
|
const originalFetch = globalThis.fetch;
|
||||||
|
globalThis.fetch = async () => { throw new Error("network down"); };
|
||||||
|
...
|
||||||
|
globalThis.fetch = originalFetch;
|
||||||
|
```
|
||||||
|
|
||||||
|
**What to Mock:**
|
||||||
|
- 外部依赖与昂贵路径:LLM、网络请求、全局单例、文件系统路径。
|
||||||
|
- 与测试目标无关的中间件/副作用(如标题生成、内存队列)应在测试中关闭。
|
||||||
|
|
||||||
|
**What NOT to Mock:**
|
||||||
|
- 核心业务状态流与事件序列(例如 `MemoryStreamBridge` 的 publish/subscribe/end 行为)。
|
||||||
|
- E2E 页面路由与关键 UI 交互链路(应尽量走真实页面流程)。
|
||||||
|
|
||||||
|
## Fixtures and Factories
|
||||||
|
|
||||||
|
**Test Data:**
|
||||||
|
```python
|
||||||
|
# backend/tests/test_client.py
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_app_config():
|
||||||
|
model = MagicMock()
|
||||||
|
model.name = "test-model"
|
||||||
|
...
|
||||||
|
return config
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// frontend/tests/e2e/support/chat-helpers.ts
|
||||||
|
export function newChatEntry(threadId: string) { ... }
|
||||||
|
export async function openChat(page: Page, url: string, options?: { expectInput?: boolean }) { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
**Location:**
|
||||||
|
- Backend 全局 fixture: `backend/tests/conftest.py`
|
||||||
|
- Backend 模块级 fixture/factory: 各 `backend/tests/test_*.py`
|
||||||
|
- Frontend E2E fixture/helper: `frontend/tests/e2e/support/chat-helpers.ts`
|
||||||
|
|
||||||
|
## Coverage
|
||||||
|
|
||||||
|
**Requirements:** 未检测到覆盖率阈值与强制 coverage 工具(无 `coverage.py`/`c8`/`nyc` 配置;CI 未执行 coverage 报告)。
|
||||||
|
|
||||||
|
**View Coverage:**
|
||||||
|
```bash
|
||||||
|
Not applicable(仓库未提供标准覆盖率命令)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Types
|
||||||
|
|
||||||
|
**Unit Tests:**
|
||||||
|
- Backend: 大量纯单测,重度使用 mock 与 monkeypatch,覆盖配置解析、middleware、tools、runtime 细节。
|
||||||
|
- Frontend: 少量模块单测,采用 Node 内置测试框架,主要覆盖上传与 stream mode 边界。
|
||||||
|
|
||||||
|
**Integration Tests:**
|
||||||
|
- Backend: `test_client_e2e.py` 定位为“中层集成”,走真实模块链路并通过环境控制是否触发真实 LLM。
|
||||||
|
- Backend: 存在 `*_live.py` 用于更高成本的真实依赖验证(如 `backend/tests/test_client_live.py`、`backend/tests/test_create_deerflow_agent_live.py`)。
|
||||||
|
|
||||||
|
**E2E Tests:**
|
||||||
|
- Frontend: Playwright 场景化用例,覆盖路由、输入、历史、artifact 面板等用户路径(`frontend/tests/e2e/*.spec.ts`)。
|
||||||
|
- 执行依赖线程相关环境变量(`FRONTEND_E2E_THREAD_ID` 等),缺失时通过 `testInfo.skip` 跳过。
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
**Async Testing:**
|
||||||
|
```python
|
||||||
|
@pytest.mark.anyio
|
||||||
|
async def test_heartbeat(bridge: MemoryStreamBridge):
|
||||||
|
await asyncio.wait_for(consumer(), timeout=2.0)
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await expect
|
||||||
|
.poll(async () => await page.locator(".is-user, .is-assistant").count(), { timeout: 30_000 })
|
||||||
|
.toBeGreaterThan(0);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error Testing:**
|
||||||
|
```python
|
||||||
|
with pytest.raises(ValueError, match="Invalid agent name"):
|
||||||
|
DeerFlowClient(agent_name="invalid name with spaces!")
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
globalThis.fetch = async () => new Response("missing", { status: 404, statusText: "Not Found" });
|
||||||
|
const converted = await promptInputFilePartToFile(...);
|
||||||
|
assert.equal(converted, null);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 分层执行与覆盖风险(可执行建议)
|
||||||
|
|
||||||
|
- 当前可稳定落地的分层执行顺序:
|
||||||
|
1. `cd backend && make lint && make test`
|
||||||
|
2. `cd frontend && pnpm format && pnpm lint && pnpm typecheck && pnpm build`
|
||||||
|
3. `cd frontend && pnpm test:e2e`(在具备线程测试数据的环境)
|
||||||
|
- 关键风险:
|
||||||
|
- Frontend 单元测试未接入统一脚本与 CI(`package.json` 无 `test` 脚本,CI 未跑 `test:e2e`)。
|
||||||
|
- 覆盖率无门槛,变更后“测试数量增长”不等于“关键路径被覆盖”。
|
||||||
|
- E2E 对外部线程数据依赖较强,易出现“跳过即通过”。
|
||||||
|
- 建议后续规划优先级:
|
||||||
|
1. 为 Frontend 增加统一单测命令并纳入 CI。
|
||||||
|
2. 在 CI 增加最小 E2E smoke(可用固定 seed 数据或 mock 后端)。
|
||||||
|
3. 引入覆盖率报告(先观测,再设阈值)。
|
||||||
|
|
||||||
|
## 简短结论
|
||||||
|
|
||||||
|
- 仓库已具备较完整 Backend 测试金字塔与前端场景化 E2E 基础,但“前端自动化测试接入 CI 不完整、覆盖率无硬约束”是当前质量收敛的主要短板。
|
||||||
|
- 后续规划应优先补齐前端测试执行入口和 CI 集成,再推进覆盖率治理,才能让测试从“存在”转为“持续有效”。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Testing analysis: 2026-04-07*
|
||||||
Loading…
Reference in New Issue