Files
deerflow-code/CLAUDE.md
T
董宏凯andClaude Opus 4.8 25e4e3dbc9 feat: 敏感词管理页面(脱敏词后台化,限 lqq 账号)
- 后端 /api/sensitive-words:全局共享词表,开放读、admin 或 lqq 整体替换写
- 前端 desensitize 种子化:SEED_DESENSITIZE_MAP + 运行时 replaceDesensitizeMap
- 启动加载后台配置回灌脱敏映射;管理页支持增删改启停 + 一键导入种子词
- 入口置于左下角设置下拉(全量/简洁两种侧边栏均有),仅用户名 lqq 可见

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 18:05:07 +08:00

9.6 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

This is a customized offline deployment of DeerFlow — a LangGraph-based AI super agent platform. The repo contains two sub-projects:

  • offline-backend-20260512/backend/ — Python backend (FastAPI Gateway + LangGraph agent runtime)
  • frontend-web/ — Vite + React 19 frontend (TypeScript, pnpm)

Managed together via shell scripts in scripts/.

Commands

Full Application (from repo root)

./scripts/start-all.sh    # Start backend + frontend as background daemons
./scripts/stop-all.sh     # Stop both
./scripts/restart-all.sh  # Restart both
./scripts/status.sh       # Check running status

Logs and PID files are written to .runtime/logs/ and .runtime/pids/.

Backend Only (from offline-backend-20260512/backend/)

make install    # Install Python dependencies (uv)
make dev        # Run Gateway API with hot-reload on port 8001
make gateway    # Run Gateway API without reload
make test       # Run all tests: PYTHONPATH=. uv run pytest tests/ -v
make lint       # Lint with ruff
make format     # Format with ruff

Run a single test file:

PYTHONPATH=. uv run pytest tests/test_<feature>.py -v

Frontend Only (from frontend-web/)

pnpm install    # Install dependencies
pnpm dev        # Start Vite dev server on port 5174
pnpm build      # Production build
pnpm typecheck  # TypeScript type checking (tsc --noEmit)

Service Ports

Service Port Notes
Backend (Gateway API) 8001 FastAPI + LangGraph runtime
Frontend (Vite) 5174 React SPA

Frontend connects to backend via env vars VITE_BACKEND_BASE_URL and VITE_LANGGRAPH_BASE_URL (injected by scripts/start-frontend.sh).

Architecture

Backend

The backend (offline-backend-20260512/backend/) is split into two layers:

  • packages/harness/deerflow/ — publishable agent framework (deerflow.* imports): LangGraph lead agent, middleware chain, sandbox, tools, MCP, memory, models, skills. Never imports from app.*.
  • app/ — application layer (app.* imports): FastAPI Gateway routers, IM channel integrations (Feishu, Slack, Telegram, DingTalk).

The Lead Agent (deerflow/agents/lead_agent/) is the single LangGraph graph entry point. It wraps a middleware chain (~18 middlewares assembled in strict order) around LLM calls, handling: thread isolation, sandbox lifecycle, uploads, memory, plan mode, vision, subagent delegation, and loop detection.

Middleware order matters — middlewares are appended in a fixed sequence; ClarificationMiddleware must always be last. See offline-backend-20260512/backend/CLAUDE.md for the full ordered list.

Harness → App import firewall is enforced by tests/test_harness_boundary.py (runs in CI).

Frontend

The frontend (frontend-web/) is a React 19 + Vite SPA:

  • Routing: React Router v7; top-level routes in src/pages/PageRoutes.tsx, workspace sub-routes in src/pages/WorkspaceRoutes.tsx
  • Pages: ChatPage (thread chat), AgentChatPage (custom agent chat), AgentsPage/NewAgentPage (agent management), ScheduledTasksPage/ScheduledTaskRunDetailPage (scheduled tasks), LightAppManagementPage/LightAppListPage/LightAppIframeView (轻应用中心 — register/list/embed mini-apps)
  • 轻应用中心 (Light App Center): a sibling of 任务管理 in the sidebar with two pages — 应用管理 (admin registers window_open or iframe mini-apps with a route-param builder: login params resolved from localStorage.userInfo, theme params literal) and 应用列表 (card grid of window_open apps, window.open launch). iframe apps are mounted under a chosen parent menu (XK/PG/TY/综合管理) and dynamically injected into the sidebar by core/page-layout/use-sidebar-menu.ts (useSidebarMenuItems), opening in the LightAppIframeView host. Client + React Query hooks in strategy-components/api/light-apps.ts; URL builder/constants in strategy-components/lib/light-app.ts. Backend: /api/light-apps (global/shared, admin-gated writes).
  • 菜单管理 (Menu Management, admin-only): an overlay over the static sidebar menu — MenuManagementPage (pages/MenuManagementPage.tsx, route /page/strategy/admin/menu-management, opened from the admin-only 「菜单管理」 item in the bottom-left settings dropdown of components/page-sidebar.tsx). Admins rename / 停用·启用 / reorder (↑↓ or @dnd-kit drag) / re-parent (horizontal drag or the edit dialog's 「移动到」parent selector) any node across 一级/二级/三级, including injected iframe light-app nodes (light-app-<appId>). The static tree (core/page-layout/sidebar-menu.ts) stays the source of icons/routes; only per-node deltas (label/disabled/parentId/sortOrder) persist to the backend. Merge logic in core/page-layout/menu-overrides.ts (applyMenuOverrides, applied in use-sidebar-menu.ts after light-app injection, before role filter; disabling a node hides its whole subtree) — strict 3-level cap (wouldExceedDepth). Client strategy-components/api/menu-overrides.ts. Backend: /api/menu-overrides (global/shared; open read, admin atomic replace-all).
  • 敏感词管理 (Sensitive Word Management): configures the 展示层脱敏映射 (原始词 → 替换词). Gated on the username lqq (not the admin role) — getAccountDisplayName().toLowerCase() === "lqq" (username = email @ prefix, else user_id, same as the profile page); the dropdown entry, the route guard, and the page-level guard all use this check. src/lib/desensitize.ts ships a frozen seed map SEED_DESENSITIZE_MAP (the deployment seed) plus a live mutable DESENSITIZE_MAP (initialized from the seed so desensitize() works before any fetch). DesensitizeWordsLoader (mounted in App.tsx AppProviders) fetches /api/sensitive-words on startup and, if non-empty, calls replaceDesensitizeMap(...) to make the backend config the source of truth (empty/failed → keep seed). Page SensitiveWordsPage.tsx (route /page/strategy/admin/sensitive-words, opened from the 「敏感词管理」 item in the bottom-left settings dropdown of components/page-sidebar.tsx, present in both full + collapsed sidebar modes) lists/adds/edits/启停/deletes words and saves the whole set atomically (replace-all); a 「导入种子词」 button merges any missing SEED_DESENSITIZE_MAP entries into the editor. Client + hooks in strategy-components/api/sensitive-words.ts (wordsToMap folds enabled rows into the runtime map). Backend: /api/sensitive-words (global/shared; open read, write allowed for admin or the lqq account), mirroring 菜单管理's store shape.
  • State: TanStack Query for server state, context providers (SubtasksProvider, ArtifactsProvider, PromptInputProvider) scoped to WorkspaceRoutes
  • LLM streaming: @langchain/langgraph-sdk streams messages from the backend via SSE
  • UI: Radix UI primitives + TailwindCSS v4 + shadcn-style components in src/components/ui/
  • Shims: src/shims/ provides next/link and next/navigation polyfills (original code was Next.js)
  • Login URL params (LoginPage.tsx, frontend-only — the backend never sees these): besides the auth params (ticket/userId/env/theme/yUserId/token/access_token/authToken/password), the page supports a task deep-link via ?taskId=&goPath=. After login it calls the consumer API GET {VITE_AIPI_CONSUMER_URL}/taskAnalyseSearch/cop-task-detail?taskId= (header Authorization: Bearer admin, auto-injected by utils/request.ts), stashes the full data (id/overview/taskDirection/taskName/taskContent) into sessionStorage["login.copTaskDetail"], then routes by goPath: base codes 3qfx/rwfx/xdfx → that business's configured single agent Q&A (resolved via /api/business-mapping, opening message in sessionStorage.pendingAgentMessage); the -A suffix (3qfx-A/…) → multi-agent roundtable with roundtablePrefill.businessCode so the page auto-selects the configured 业务链条. goPath→businessCode: 3qfx→3Q, rwfx→6BF, xdfx→7BF. Both targets render embedded under the 任务管理 layout — nested routes under task-management/<business-path>/{roundtable,agent/:agent_id/chats/:thread_id} in StrategyRoutes.tsx (<business-path> = plan-task-sentiment / plan-task/plan-task-fx / plan-task/plan-task-action, matching the COH中任务 menu paths in sidebar-menu.ts) so the global sidebar keeps 任务管理 → COH中任务 → the matching business highlighted. The agent chat is rendered via TaskEmbeddedAgentChat, which passes AgentChatPage's chatBasePath prop so the post-send URL rewrite + new-chat button stay in the task-management context (instead of the standalone /agents/... route). Any failure (no consumer URL / fetch error / unmapped goPath / no configured agent) silently falls back to the default home. Helpers: core/auth/task-deeplink.ts.

Configuration

Backend config lives in offline-backend-20260512/backend/config.yaml. Values starting with $ resolve as environment variables (e.g., $OPENAI_API_KEY). MCP servers and skills are configured in extensions_config.json in the same directory.

Detailed Backend Reference

The backend has its own comprehensive documentation at:

  • offline-backend-20260512/backend/CLAUDE.md — architecture, middleware chain, all API routes, config schema, sandbox/memory/subagent systems
  • offline-backend-20260512/backend/README.md — setup guide, technology stack