mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-11-12 22:20:33 +00:00
* docs: turn README into an index and move reference detail to docs/guide The README had grown to 393 KB because every change appended its notes there. The text moves verbatim into 18 topic guides under docs/guide/; only headings are re-leveled and relative links re-pointed. The README keeps the introduction, a quick start and a guide index. Contributor test notes move to CONTRIBUTING.md. * docs: send user docs to topic guides and budget the root README The rule 'update README.md for user-facing changes' is what grew the README. Guidance now points to docs/guide/, and check_agent_guidance.py fails when the root README exceeds 16 KiB (AG003). * chore: remove unreferenced screenshots and finished plan notes pr-build/ holds two PR screenshots (3 MB) from #1986. plans/ holds the plan for the merged #4049. docs/SKILL_NAME_CONFLICT_FIX.md is a February change note. Nothing references them. * docs: route always-loaded AGENTS.md files to scoped guides * docs(agents): cut scoped guides to scope, verify, traps, decisions Each AGENTS.md keeps four kinds of content: the scope of the directory, the verification commands, traps a local test run does not show, and decisions the code cannot state. Values, field lists, function inventories, test names, issue numbers and history are deleted, because the code, the tests and git state them. Search and fetch providers share one community guide. Four guides with no remaining content are removed. The size check now allows 6 KiB per file (hard limit 8 KiB) and 24 KiB per chain (hard limit 32 KiB). * style: format frontend guide table and guidance test imports --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
5.0 KiB
5.0 KiB
Frontend source (frontend/src/)
app/ holds routes, components/workspace/ the chat UI, and core/ the
framework-free logic (threads, messages, API client, settings). Ownership of the
model picker, chat entry pages, branch tree and browser control is described in
conversation-ui-ownership.md.
Verify
cd frontend
pnpm check # eslint + tsc
pnpm rstest run <pattern> # unit and happy-dom tests under tests/unit
pnpm test:e2e # Playwright, for anything that depends on a real browser
Threads and streaming
- Two thread identities. A new chat has a display ID before the SDK has a
threadId. Key local-turn state on the displayed conversation so that it survives the moment the SDK ID appears. - Creating a run is not retried. Only the first
POST /runs/streamhas retries off, because a retry after an ambiguous failure creates a second run. Stream reads keep the SDK retry budget. - A stream gap is not the end of a run. When the server reports a replay gap, reload durable state and rejoin. Do not finish the turn and do not cancel the backend run.
- Do not rejoin a completed run. Recovery for a reopened chat lists active runs, and that read can be stale. Run IDs that the mounted hook has seen complete stay excluded.
- Unsupported stream modes fail before the request. Forwarding part of the
list, or defaulting to
values, hides a caller bug. - Stream updates use the SDK
throttle: truemode. A numeric delay changes the trailing-debounce behaviour on a continuous stream; validate that before you switch. - No timers during render. Streamed tool updates re-render often. Schedule timers in an effect with cleanup.
- Queue and Steer. Release a rejected attempt only after an HTTP 409 with no recovered receipt. After an uncertain failure keep its run, request ID and draft, because the server may have accepted the input.
Messages
- Match by message ID. History, checkpoint and live copies of a message are overlaid by message ID. Provider tool-call IDs repeat across runs.
- One message, two renderers. A tool-calling AI message can also carry visible text, and a streaming text message can gain tool calls later. It is drawn by the processing group first and by the settled bubble afterwards, so text and reasoning order must be the same in both.
- Run-scoped displays have one anchor. Duration and workspace-change badges
belong to a run, and a run can end in several assistant bubbles. Choose the
anchor in
core/messagesand render it once. - Tool failures come from structured status. Use
core/messages/tool-error.ts. Classifying result text marks normal output as an error. - Exports read every persisted page. The loaded window and the compacted checkpoint both omit messages.
State and storage
- Server state is authoritative.
ThreadState.artifactsis the artifact list. Session storage keeps panel UI state only, and an empty first stream value must not overwrite restored state before history loads. - A truncated preview is never an editing baseline. Its ETag can equal the full file's. Editing and saving need the complete content.
- Account preferences are scoped to the account. A late response for a previous account is dropped, and legacy unscoped settings are never uploaded. Automatic model or mode resolution writes nothing to the account. Only an explicit user choice does.
- Composer drafts are per tab. New-chat pages use a stable scope because their runtime thread ID changes on every reload.
- Credentials stay out of browser storage. The session and CSRF cookies belong to the Gateway.
Untrusted input
- Links in tool steps and Markdown come from the model or a provider. Pass them
through the shared
isSafeHrefallowlist and render rejected ones withUnsafeLink. - Knowledge sources come only from native tool artifacts. Message text and metadata cannot create a source. Excerpts render as plain text.
- Plugin mention IDs, imported Agent packages and uploaded names are input for the Gateway to validate. They grant nothing in the UI.
- Maps keyed by external strings use own properties, so
constructorand__proto__fall back like any unknown key.
Rendering
- Server Components by default.
app/layout.tsxreads no cookies and imports no chat-only styles, so the public/stays static. - Build chat paths with
core/threads/utils.ts::pathOfThread(). It encodes agent names and thread IDs. - Streaming Markdown plugins come from the shared
core/streamdownconfig. Keep wrapper behaviour in workspace components and leave the generated AI elements unedited. - The three right-hand panels share one
ResizablePanelGroupinchat-box.tsx. A separate branch per panel loses the drag handle. - Composer permission checks run in
InputBox.handleSubmitafter the command is classified and before the thread is prepared or the draft cleared.