mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-18 18:46:17 +00:00
* perf(frontend): coalesce streaming renders to a frame budget instead of per chunk While a run streams, the merge/group/render pipeline consumed every SSE chunk as its own React update (~60/s), re-rendering the whole thread tree per token. Enable the SDK's same-tick batching (throttle: true) and publish the render-facing messages snapshot at most once per 80 ms with a leading edge and a trailing flush, keyed through a memoized merge so identities stay stable between flushes. Lifecycle consumers (optimistic clearing, summarization capture, usage baselines) keep reading the per-chunk array. * perf(frontend): keep the transient bridge order array identity stable mergeTransientHistoryBridgeOrder cloned unconditionally, so the render-time call handed the coalesced merge memo a fresh array identity on every render while the transient history bridge was open, re-running mergeMessages between flushes. Clone lazily and return the input order when nothing is appended; the merge only ever appends, so an unchanged length means unchanged content. Consumers only read the returned order, so reusing the input is safe. * perf(frontend): drive the render coalescer from a monotonic clock The coalescing interval was measured with Date.now(). A backward wall-clock step (NTP correction, sleep/wake) turns the elapsed term negative, so the scheduled delay becomes interval + jump and the rendered snapshot stalls for the length of the jump. Read performance.now() once per effect invocation instead; the timer callback re-reads it because timers fire late and the next interval must start from the real flush. Seed the last-flush marker with -Infinity so the first update of a stream still takes the leading edge under a page-load-relative clock. * perf(frontend): reset the coalescer flush baseline when a stream ends The leading-edge flush was scoped to the hook instance rather than to each stream: a run starting within one interval of the previous one found a recent flush baseline and deferred its first frame. Drop the baseline when leaving the streaming state so every stream opens on the leading edge. * perf(frontend): disarm the trailing flush when the leading edge wins decideCoalesce checks the elapsed interval before the pending-timer flag, so an update arriving past the interval takes the leading edge while a trailing timer is still armed. Timers fire late under main-thread load -- exactly the regime this coalescer targets -- so that timer then publishes a second time and slips the flush baseline forward, breaking the at-most-one-flush-per- interval property when it matters most. Disarm the pending timer in the flush-now branch, and cover the previously untested elapsed >= interval && hasPendingTimer quadrant. * perf(frontend): stop syncing the render snapshot while idle The snapshot is only read while streaming, so keeping it current on every idle messages change costs one wasted render per history refetch or thread navigation. Dropping that publish outright is not safe either: the leading edge runs in a passive effect, but the render where isStreaming flips true paints first and returns the snapshot, so a stale one would be painted -- after a thread switch, another thread's messages, since the chat page deliberately avoids re-mounting on navigation. Make the snapshot nullable, where null means no snapshot belongs to the current stream, and return the live array while it is null. The idle branch then writes state once per stream end instead of once per idle update, and the stale-frame window does not exist rather than being short.
DeerFlow Frontend
Like the original DeerFlow 1.0, we would love to give the community a minimalistic and easy-to-use web interface with a more modern and flexible architecture.
Tech Stack
- Framework: Next.js 16 with App Router
- UI: React 19, Tailwind CSS 4, Shadcn UI, MagicUI and React Bits
- AI Integration: LangGraph SDK and Vercel AI Elements
Quick Start
Prerequisites
- Node.js 22+
- pnpm 10.26.2+
Installation
# Install dependencies
pnpm install
# Copy environment variables
cp .env.example .env
# Edit .env with your configuration
Development
# Start development server
pnpm dev
# The app will be available at http://localhost:3000
Build & Test
# Type check
pnpm typecheck
# Check formatting
pnpm format
# Apply formatting
pnpm format:write
# Lint
pnpm lint
# Run unit tests
pnpm test
# One-time setup: install Playwright Chromium browser
pnpm exec playwright install chromium
# Run E2E tests (builds and starts production server automatically)
pnpm test:e2e
# Build for production
pnpm build
# Start production server
pnpm start
Site Map
├── / # Landing page
├── /chats # Chat list
├── /chats/new # New chat page
└── /chats/[thread_id] # A specific chat page
Configuration
Environment Variables
Key environment variables (see .env.example for full list):
# Backend API URL (optional, uses local Next.js/nginx proxy by default)
NEXT_PUBLIC_BACKEND_BASE_URL="http://localhost:8001"
# LangGraph-compatible API URL (optional, uses local Next.js/nginx proxy by default)
NEXT_PUBLIC_LANGGRAPH_BASE_URL="http://localhost:8001/api"
Project Structure
tests/
├── e2e/ # E2E tests (Playwright, Chromium, mocked backend)
└── unit/ # Unit tests (mirrors src/ layout)
src/
├── app/ # Next.js App Router pages
│ ├── api/ # API routes
│ ├── workspace/ # Main workspace pages
│ └── mock/ # Mock/demo pages
├── components/ # React components
│ ├── ui/ # Reusable UI components
│ ├── workspace/ # Workspace-specific components
│ ├── landing/ # Landing page components
│ └── ai-elements/ # AI-related UI elements
├── core/ # Core business logic
│ ├── api/ # API client & data fetching
│ ├── artifacts/ # Artifact management
│ ├── config/ # App configuration
│ ├── i18n/ # Internationalization
│ ├── mcp/ # MCP integration
│ ├── messages/ # Message handling
│ ├── models/ # Data models & types
│ ├── settings/ # User settings
│ ├── skills/ # Skills system
│ ├── threads/ # Thread management
│ ├── todos/ # Todo system
│ └── utils/ # Utility functions
├── hooks/ # Custom React hooks
├── lib/ # Shared libraries & utilities
├── server/ # Server-side code
│ └── better-auth/ # Authentication setup and session helpers
└── styles/ # Global styles
Scripts
| Command | Description |
|---|---|
pnpm dev |
Start development server with Turbopack |
pnpm build |
Build for production |
pnpm start |
Start production server |
pnpm test |
Run unit tests with Rstest |
pnpm test:e2e |
Run E2E tests with Playwright |
pnpm format |
Check formatting with Prettier |
pnpm format:write |
Apply formatting with Prettier |
pnpm lint |
Run ESLint |
pnpm lint:fix |
Fix ESLint issues |
pnpm typecheck |
Run TypeScript type checking |
pnpm check |
Run both lint and typecheck |
Development Notes
- Uses pnpm workspaces (see
packageManagerin package.json) - Turbopack enabled by default in development for faster builds
- Environment validation can be skipped with
SKIP_ENV_VALIDATION=1(useful for Docker) - Backend API URLs are optional; nginx proxy is used by default in development
License
MIT License. See LICENSE for details.