deer-flow/CHANGELOG.md
Hyeonsang Cho bbced51022
fix(gateway): close two input-sanitization bypasses (#5375)
* fix(gateway): reject forged framework-injection markers in run input

`is_genuine_user_message` treats `hide_from_ui` and a human `name="summary"`
as proof the framework authored a message, and `InputSanitizationMiddleware`
skips those — escaping a real reminder's blocks would corrupt trusted context.
Neither marker was server-owned, so an external caller could set either one and
place a raw `<system-reminder>` outside the user-input boundary markers, which
the lead-agent system prompt declares trusted internal framework data. The
`hide_from_ui` variant is also filtered out of the thread UI, so the forgery
was invisible where it landed.

Both markers are now stripped from untrusted input, on the run path and on the
thread-state mutation route that writes straight into a checkpoint. Framework
injection happens inside the graph and never crosses this boundary, so nothing
the framework does is affected, and `trusted_internal` callers (IM channels,
the MCP task-notification launcher) keep writing hidden messages.

HumanInputCard replies are the one legitimate external `hide_from_ui`: the
frontend sends it alongside a `human_input_response` payload, so a message
carrying a valid one keeps the marker. That buys no bypass — the predicate
already classifies those as genuine, so they stay sanitized.

The name check reuses the predicate's own `_SUMMARY_MESSAGE_NAME` rather than a
fourth copy of the literal, and matches by `isinstance` exactly as the predicate
does: `HumanMessageChunk` is a `HumanMessage` whose `type` is not `"human"`, so
a type-based check would leave that subclass's marker settable. `name` is only
reserved on human messages — on a ToolMessage it is the tool's own name.

Three tests in test_gateway_services.py and test_message_provenance.py asserted
that a caller-supplied `hide_from_ui` survives. That assumption was the bypass;
they now pin the opposite, with a genuinely caller-owned key kept alongside to
prove the stripper is surgical.

* fix(agents): sanitize every genuine user message, not only the newest

The input guardrail scanned backwards for the first genuine user message and
returned, so only the newest turn was ever sanitized. The transformation is
request-scoped (`wrap_model_call`, never written to state), so thread state
keeps the raw text: once a newer turn arrived, the previous turn's payload was
replayed to the model verbatim, outside the boundary markers the lead-agent
prompt declares trusted framework data. The guardrail therefore held for
exactly one model call.

Reaching it needed no forged metadata and no crafted request body — type the
payload in one turn, then send anything at all in the next. A single request
carrying two user messages did it in one shot, since every message but the last
was skipped.

`_process_request` now walks the whole list and `_sanitize_message` owns the
per-message work; every existing branch (the `original_user_content` split for
upload turns, the multimodal rfind fallback, the metadata repair) is unchanged.
Framework-injected messages stay excluded by `is_genuine_user_message`.

Unexpected errors now fail open per message rather than per request. Iterating
history widened the old blast radius: one unprocessable row would have dropped
sanitization for the whole request, handing an attacker the newest turn by
crafting an older one. `GraphBubbleUp` still propagates.

Side effect worth noting: each turn's rendering is now stable across model
calls. Previously a turn was wrapped on its own call and unwrapped on the next,
changing the prompt prefix behind the newest turn and defeating prompt caching.

test_only_processes_last_user_message pinned the old scope; it now pins that
every turn is processed, and keeps driving the `wrap_model_call` entry point.

* docs: record the message-metadata trust boundary and sanitization scope

`agents/middlewares/AGENTS.md` owns the depth for InputSanitizationMiddleware
and documented only the `original_user_content` half of its trust boundary. Left
alone it would teach an agent that `hide_from_ui` is caller-owned and that the
guardrail covers one turn — and the usual failure mode is an agent "restoring"
the behaviour it believes was lost. The entry now carries both markers, the
HumanInputCard exception, the whole-history scope, and the per-message fail-open
rule.

The note lives only there. The root and `backend/AGENTS.md` layers are
orientation that points at the module guides owning the depth, and
`backend/AGENTS.md` is inherited by every backend chain — prose added there
inflates more than twenty of them, and `scripts/check_agent_guidance.py` shows
the middlewares chain has about a kilobyte of room against its hard limit.

CHANGELOG.md and CHANGELOG_zh.md record it under Security, continuing the
existing prompt-injection lineage.

* fix(gateway): mark caller-hidden messages instead of stripping the marker

Review follow-up. Stripping a caller-supplied `hide_from_ui` closed the bypass
but broke three frontend senders that use the marker purely to keep a context
message out of the transcript: the quoted conversation context
(`buildHiddenConversationQuoteMessage`), the sidecar context prompt
(`buildHiddenSidecarContextMessage`), and the agent save command. None carries a
`human_input_response`, so the HumanInputCard carve-out did not cover them, and
nothing else hides them — `_is_branch_visible_message` and the frontend's
`isHiddenFromUIMessage` both key solely on `hide_from_ui`, and no backend reads
`conversation_quote_context` or `sidecar_context`. All three would have rendered
as user-visible chat bubbles.

The marker plays two roles and only one of them is a vulnerability. The security
requirement is that a caller-supplied marker cannot skip sanitization, not that
it cannot hide a message. So the roles are separated instead of the marker being
removed: the Gateway keeps it and stamps the server-owned `UNTRUSTED_INPUT_KEY`,
and the guardrail now asks `requires_input_sanitization` — the mark, else the
genuine-user test. Hidden stays hidden; untrusted content is sanitized either
way. The reserved `summary` name is handled the same way and no longer rewritten.

Marking rather than removing is also the safer shape in general: `hide_from_ui`
is read for presentation, journal persistence, memory filtering and IM outbound
as well, and this boundary should not silently change any of them.

`is_genuine_user_message` is deliberately left alone. `ToolReceiptMiddleware`
uses it for turn-boundary detection, where a caller's hidden context message must
keep counting as not user-authored; widening it there would move the ledger's
turn window. `requires_input_sanitization` sits beside it in `message_utils` so
the two questions can be compared.

The three tests that asserted a caller-supplied `hide_from_ui` is removed now
assert it survives and carries the mark — which restores the original intent of
the two provenance cases, whose comment already read "caller-owned keys must
survive".

* docs(gateway): rewrite normalize_input's docstring around the mark

Review follow-up. The paragraph still described the pre-4a3344f6 strip model and
contradicted both the implementation and the middlewares AGENTS.md paragraph
updated in that same commit: it called `hide_from_ui` server-owned, said
carrying it skips sanitization entirely, and repeated the premise this branch
disproved — that HumanInputCard replies are the only legitimate external use.

It now describes what the code does: the markers stay caller-owned and are
preserved because three frontend senders rely on `hide_from_ui` for hiding
alone, the message is stamped with `untrusted_input` instead, and
`requires_input_sanitization` sanitizes it anyway. `untrusted_input` joins the
server-owned inventory in the preceding paragraph, which is what makes the stamp
unforgeable and unclearable.

The three surrounding docstrings now also say that these functions mark as well
as strip; `_strip_external_message_metadata` had advertised only the removal,
leaving a reader no way to find the stamp from the name.

* fix(gateway): mark state writes whose message omits additional_kwargs

Review follow-up. The state-route half of the fix missed the most natural
request shape. `_strip_external_metadata_from_message_like` returned early when
`additional_kwargs` was absent or not a dict — there was nothing to strip — and
that early return also skipped the mark. A `POST /threads/{id}/state` body of
`{"values": {"messages": [{"role": "user", "name": "summary", "content":
"<system-reminder>…</system-reminder>"}]}}` therefore reached the checkpoint
unmarked. The messages reducer's `convert_to_messages` then supplies
`additional_kwargs={}`, so at model-call time `requires_input_sanitization` fell
back to `is_genuine_user_message`, which a `summary` name fails, and the forged
tag reached the model raw and outside the boundary markers.

A missing or non-dict `additional_kwargs` is now treated as empty for both the
strip and the mark. The identity return is kept for the case where nothing
changes, so an ordinary key-omitted message does not gain an empty dict just by
passing through. The run path was never affected: `normalize_input` coerces to
BaseMessage first, which always carries the dict.

Every existing state-write test supplied an `additional_kwargs` dict, which is
why this shape slipped through; the regression now covers it at the route and
end to end through the reducer into the guardrail.

While checking the neighbouring shapes, `_skips_input_guardrail` keyed off key
presence where `is_genuine_user_message` keys off truthiness, so
`hide_from_ui: False` — already covered without a mark — would have been
stamped. It now mirrors the predicate exactly, as its docstring claimed.

* docs(middlewares): compress the sanitization note to fit the guidance chain

main's growth left the middlewares AGENTS.md chain 84 bytes under its hard
limit, and the fuller wording did not fit. The load-bearing facts stay — the
markers are marked rather than stripped, and the scan covers every turn — since
those are the two an agent editing this middleware could otherwise get wrong.
The full model lives in the normalize_input, _mark_untrusted_framework_markers
and requires_input_sanitization docstrings.

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-09-14 09:54:42 +08:00

2822 lines
166 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Changelog
All notable changes to DeerFlow are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
This section accumulates work toward the **2.1.0** milestone
([milestone 2](https://github.com/bytedance/deer-flow/milestone/2)).
### ⚠ Breaking changes
- **gateway:** Request trace ids are now issued unconditionally, and every
Gateway HTTP response carries an `X-Trace-Id` header. Previously both were
gated behind `logging.enhance.enabled`, which now controls **log output
only** — whether records carry a `trace_id` field, and in which format. The
header cannot be turned off; installations running the default
`enabled: false` will start seeing it after upgrading. Scheduled tasks, MCP
task notification runs, IM channel messages, and the embedded
`DeerFlowClient` bind an id per unit of work, so the id also reaches the run
record, the checkpoint metadata, and Langfuse traces that previously had
none. A `deerflow_trace_id` supplied in a run request's `metadata` or
`config.context` is now ignored and overwritten so the response header, the
logs, and the persisted run cannot disagree — send the `X-Trace-Id` request
header to pin a correlation id across services. `logging` remains
restart-required. No config keys were added or removed. ([#5119])
- **skills:** Sandboxes now reserve `/mnt/skills` for managed enabled-only
projections. `DEER_FLOW_HOST_SKILLS_PATH` and `SKILLS_HOST_PATH` are no longer
used; Docker/AIO and hostPath deployments derive projection paths from
`DEER_FLOW_HOST_BASE_DIR`. E2B operator mounts targeting `/mnt/skills` or any
child path are skipped with a warning so they cannot shadow the managed
projection; move extra E2B content to a different container path. User
projections re-read global enable state from disk so toggles propagate across
Gateway workers on the next sandbox acquire. Existing E2B sandboxes retain
their creation-time snapshot until they are recreated. PVC-backed provisioner
deployments still mount the operator-supplied PVC snapshot directly, so
disabled-skill filesystem isolation does not apply in PVC mode until dynamic
PVC materialization is implemented. ([#4178])
- **sandbox:** E2B now enforces `sandbox.replicas` as a process-local capacity
limit. The default `wait` policy waits for `acquire_timeout`, then fails the
agent turn. DeerFlow does not retry the turn automatically. Use `burst` with
`burst_limit` to permit bounded extra VMs. The `reject` policy can remove one
warm VM before it returns a capacity error. ([#4391])
- **skills:** A directory containing `SKILL.md` is now a runtime package
boundary. Nested `SKILL.md` files inside that package are supporting data and
are no longer registered as independent skills; unusual custom layouts must
move independently loadable skills under a namespace directory without its
own `SKILL.md`. ([#4098])
- **memory:** The memory system is now pluggable (`memory.manager_class` selects
a backend; default `deermem` is self-contained). DeerMem-private settings moved
from the top level of `memory:` into `memory.backend_config`, and the
`/memory/config` response (and `client.get_memory_config()`) changed shape.
([#4122])
- **memory:** `/memory/config` and `client.get_memory_config()` no longer return
flat DeerMem fields (`storage_path`, `max_facts`, `debounce_seconds`,
`token_counting`, `guaranteed_*`, `staleness_*`, ...). They return
`{enabled, mode, injection_enabled, manager_class, backend_config}` where
`backend_config` is an opaque dict the active backend self-interprets. Memory
*data* responses (`/memory`, `/memory/status` data) are unchanged. External
API/SDK clients reading the old flat fields must read `backend_config` instead.
([#4122])
- **memory:** Custom `memory.storage_class` moved: the old default path
`deerflow.agents.memory.storage.FileMemoryStorage` no longer exists (now
`deerflow.agents.memory.backends.deermem.deermem.core.storage.FileMemoryStorage`).
Custom `MemoryStorage` subclasses must accept `config` in `__init__` (was
no-arg). A broken/old `storage_class` logs an error and falls back to
`FileMemoryStorage` (won't crash) -- update the path + signature to restore it.
([#4122])
- **memory:** `storage_path` semantics changed from a FILE path to a root
DIRECTORY. Pre-abstraction, an absolute `storage_path` was the shared memory
file (opting out of per-user isolation) and a relative value was the global
file under the data base_dir. Now `storage_path` (absolute or relative) is the
root directory; per-user memory lives at `{storage_path}/users/{uid}/memory.json`.
An upgrade keeping the old default `storage_path: memory.json` (a relative file
name) would orphan per-user memory or hit `NotADirectoryError` on save, so the
legacy migration **drops file-style `storage_path` values (ending in `.json`)
with a warning** and the factory **raises** if `storage_path` resolves to an
existing file. Set `memory.backend_config.storage_path` to a directory for a
custom root. ([#4122])
- **memory:** `memory.mode: tool` with a backend that does not implement
`search()` now fails fast at Gateway startup with a `ValueError` from the
`MemoryManager` invariant, instead of starting successfully and silently
returning empty results on every `memory_search` call. Both shipping backends
implement `search()` (DeerMem retrieves; `noop` returns `[]`), so this only
affects a custom backend that onboards without overriding `search()`. It is
intentional -- silent empties are worse than a loud startup error. Fix: switch
to `mode: middleware` or override `search()` (and set `supports_search=True`).
([#4324])
- **config:** `database.checkpoint_delta_snapshot_frequency` moved to
`database.checkpoint_delta.snapshot_frequency` and its default changed from
`1000` to `10`. A legacy top-level value is still honored with a deprecation
warning and mapped onto the nested key (an explicitly set nested key wins).
Deployments that relied on the old default now snapshot 100x more often in
delta mode -- set `database.checkpoint_delta.snapshot_frequency: 1000`
explicitly to keep the previous cadence. ([#4516])
- **docker:** The published entry port now binds to loopback (`127.0.0.1`) by
default in both compose files, matching the documented local-trust deployment
model. Deployments that relied on the old `0.0.0.0` binding must set
`BIND_HOST` to expose the stack on other interfaces. ([#4618])
### Added
#### Scheduler
- **scheduler:** Scheduled tasks accept `interval` (`schedule_spec.every_seconds`)
in addition to `once` and `cron`. Cadence is UTC `now + N` with no missed-beat
catch-up. N is at least `scheduler.min_once_delay_seconds` (default 60s) and at
most 30 days.
#### Authentication
- **auth:** Personal access tokens (PAT) for programmatic API access:
`POST/GET/DELETE /api/v1/auth/pats` manage tokens (shown once, stored as
SHA-256 digests); a default-deny route policy admits only the thread/run
lifecycle routes, narrowed further by the token's `threads`/`runs` scopes,
and any request dimension that carries cancel capability (`?action=`,
`multitask_strategy`) additionally requires `runs:cancel`. ([#5041])
- **auth:** Login throttling parameters are configurable via
`auth.local.max_login_attempts` (default 5, min 2) and
`auth.local.lockout_seconds` (default 300), resolved live so a config reload
applies on the next login without a Gateway restart — the unblock path for
deployments behind corporate proxies/NAT where many users share one egress
IP. Defaults are unchanged. ([#5110])
#### Agents & runtime
- **scheduler:** Scheduled tasks can pin `assistant_id` to `lead_agent` (the
default) or a custom agent the owner already has. Unknown or malformed names
return 422. The workspace create/edit form exposes the same choice.
([#5286])
- **gateway:** `GET /api/threads/{thread_id}/runs/page` walks thread run history
with a `(created_at, run_id)` keyset cursor (`{data, has_more,
next_before_created_at, next_before_run_id}`). `GET /api/threads/{thread_id}/runs`
still returns a bare array of the newest 100 runs so LangGraph SDK clients keep
working. ([#5282])
- **middleware:** New `TokenBudgetMiddleware` enforces a per-run token budget,
shared additively across the lead agent and subagents. ([#3412])
- **middleware:** Structured tool-result metadata and a tool-progress state
machine give the runtime first-class visibility into multi-step tool flows.
([#3601])
- **context:** Record the effective memory identity per run and persist durable
context (system messages, memory, and tool state) across summarization,
emitting it as structured runtime metadata so compaction no longer drops it.
([#3556], [#3887], [#3906])
- **runtime:** Goal continuations let a run resume toward a goal across multiple
agent turns, with `continuation_count` tracked and capped. ([#3858])
- **subagents:** A system-maintained delegation ledger prevents redundant
re-delegation of an in-flight task, and a total delegation cap bounds fan-out
per run. ([#3877], [#4115])
- **subagents:** Persist and display subagent step history in the thread.
([#3845])
- **tools:** Structured synopses replace raw oversized tool output in previews.
([#3377])
- **files:** Deterministic read-before-write version gate for file tools
prevents clobbering concurrent edits. ([#3912])
- **gateway:** Cache-aware cost accounting attributes token costs to cached vs.
uncached paths; a Redis stream bridge enables distributed event streaming; and
manual context compaction is exposed to the user. ([#3920], [#3191], [#3969])
- **gateway:** The stream-bridge heartbeat interval is configurable via
`stream_bridge.heartbeat_interval_seconds` (default 15s), so deployments
behind aggressive proxy idle timeouts can tune SSE, `/wait`, and internal
subscribers together. ([#5017])
- **runtime:** Dual-mode checkpoint storage with LangGraph `DeltaChannel` cuts
thread storage from O(N²) to near-linear for long research/coding runs.
([#4292])
- **runtime:** Delta-mode checkpoint history cache (memory/redis) with O(1)
incremental composition, configured via `database.checkpoint_cache`. ([#4638])
- **agent:** Config-declared lead-agent middlewares let deployments add custom
`AgentMiddleware` classes without patching the runtime chain. ([#3964])
- **agents:** Per-agent model and generation settings (`temperature`,
`max_tokens`, `thinking_enabled`, `reasoning_effort`) override the shared
model profile. ([#4347])
- **runtime:** Record terminal artifact-delivery receipts so runs expected to
`present_files` no longer report success when delivery fails. ([#4365])
- **uploads:** Lazy-load historical files via a `list_uploaded_files` tool
instead of injecting the full manifest. ([#4174])
- **scheduler:** `scheduler.recursion_limit` in `config.yaml` sets the LangGraph
super-step cap for scheduled runs (default 1000, matching the web UI's
interactive budget, clamped by `max_recursion_limit`). ([#4848])
- **runtime:** Every tool call now carries a runtime-stamped, tamper-evident
tool receipt, and a bounded receipt ledger is injected into the model
context so agents can cite execution evidence in their reports. Enabled
by default via the new `verification` config section. ([#4659])
- **subagents:** Subagent delegations are now verifiable, layering RFC #4651:
every subagent's report contract requires citing tool receipts (e.g.
`[r3 write_file]`) and attaching a verifiable handle to each deliverable,
the lead agent cross-checks those citations against the subagent's actual
execution record, and `acceptance_criteria` on a `task` delegation are
checked deterministically parent-side (file existence/non-emptiness,
recorded test-command exit status) with anything undecidable reported
UNVERIFIED instead of silently passed. ([#5076], [#5090], [#5109])
- **clarification:** Human-input (clarification) cards support structured
form fields, so an agent can request exactly the input it needs instead
of free text only. ([#4406])
- **subagents:** Built-in subagents now receive the current-date context
anchor, so delegated tasks involving relative dates behave like tasks the
lead agent handles directly. ([#4797])
- **subagents:** A Settings page manages a deployment-level Subagent catalog
(admin-managed worker definitions alongside built-in and `config.yaml`
ones), and Custom Agents can restrict delegation to an explicit worker
allowlist enforced at both prompt and execution time. ([#4887])
- **subagents:** Subagent concurrency is now governed by one process-wide
capacity controller, and an opt-in `batch_task` tool runs large
collections of independent items as durable, resumable SQL-backed batches
with leases, bounded retries, pause/resume/cancel, and a chat panel for
tracking progress. ([#4998])
- **agents:** The current-date context injected into lead- and subagent
prompts honors the optional `DEER_FLOW_DATE_TIMEZONE` env var (IANA name,
e.g. `Asia/Shanghai`), so users in non-UTC deployments are no longer told
the wrong "today" around midnight; unset keeps server-local behavior.
([#5154])
- **subagents:** Delegated subagents can discover files uploaded in earlier
turns: the parent run's validated `uploaded_files` boundary seeds the
subagent's graph state, making `list_uploaded_files` eligible for normal
tool-policy filtering (durable `batch_task` workers keep it disabled).
([#5170])
- **agents:** The read-before-write gate now elides the dead payload of a
blocked `write_file` / `str_replace` call (`content`, `old_str`, `new_str`)
from model-bound requests. A blocked call never ran and must be re-issued
after a re-read, so the original arguments only cost context; stored
history, receipts, and the run journal keep them. Blocked results are
paired with call occurrences (tool-call ids may repeat across turns), and
a request whose history was rewritten drops OpenAI `resp_` response ids so
`use_previous_response_id` chaining cannot resume the original server-side
history. Controlled by `read_before_write.elide_blocked_payloads` (default
on) and `read_before_write.elide_min_chars` (default 2000).
- **agents:** `ToolOutputBudgetMiddleware` now also elides the `content` of a
successful `write_file` call from model-bound requests once the same path
was read or modified again later in the conversation. After a successful
write the file on disk is the source of truth, and the read-before-write
gate forces a `read_file` before the next modification, so the historical
copy was redundant with that read and long report-writing runs carried every
section twice. The newest `tool_output.keep_recent_writes` successful writes
(default 1) always stay visible, `str_replace` payloads are never touched,
and stored history, receipts, and the run journal keep the original
arguments. Controlled by `tool_output.elide_superseded_writes` (default on)
and `tool_output.superseded_write_min_chars` (default 2000).
#### Memory
- **memory:** Memory consolidation synthesizes fragmented facts, and a staleness
review prunes silently-outdated facts using LLM-assigned per-fact
`expected_valid_days` / `staleFactsToExtend`. ([#3996], [#3860], [#4143])
- **memory:** Guaranteed injection of correction facts (with graceful fallback)
so user corrections always reach the model. ([#3592])
- **memory:** Slim the pluggable `MemoryManager` interface for backend
onboarding - new backends no longer implement unused abstract methods, and
DeerMem-specific hook injection moves out of the shared factory. ([#4326])
- **memory:** Incremental agent-scoped Markdown fact storage isolates per-agent
facts and updates a single fact without rewriting or reindexing the whole
collection. ([#4279])
- **memory:** Memory message processing adds a conversation watermark,
trivial-turn filtering, and a durable queue so extraction no longer re-feeds
the full conversation every turn. ([#4447])
- **memory:** A built-in FTS5/BM25 retrieval adapter provides full-text
search over stored memories without an external retrieval service.
([#4360])
- **memory:** New pluggable memory backends: OpenViking and mem0 over HTTP,
plus Honcho as a user-model memory provider. ([#4509], [#4528], [#4730])
- **memory:** A hybrid fact eviction policy blends multiple signals when
deciding which stored facts to drop as memory fills. ([#4789])
#### Skills
- **skills:** The built-in image-generation skill can use OpenAI-compatible
Images APIs for generation and reference-image editing, with configurable
endpoint, model, size, and output format.
- **skills:** Native SkillScan (phase 1) statically analyzes skill packages at
load, and `describe_skill` enables deferred discovery so the model fetches a
skill's schema on demand instead of loading all skills up front. ([#3033],
[#3775])
- **skills:** Per-user custom skill isolation with sandbox mounting. ([#3889])
- **skills:** The skill list reopens after a skill is selected, so several
skills can be attached in a row. ([#4639])
- **skills:** Install local `.skill` archives directly from the Skills
settings page, reusing the existing per-user installer and security scan.
([#5039])
- **skills:** Podcast-generation Volcengine voices are configurable per
speaker gender, with trimmed blank-safe defaults. ([#5156])
#### Models & integrations
- **community:** New web search/fetch engines - GroundRoute, Crawl4AI
(`web_fetch`), and a fastCRW provider - plus a Browserless `web_capture`
screenshot tool and Brave `image_search`. ([#3675], [#3821], [#3585], [#3881],
[#3866])
- **mcp:** Per-server `tool_call_timeout` for MCP tool calls, and routing hints
that guide the model to the right server. ([#3843], [#4004])
- **mcp:** Add an official OpenViking `/mcp` example that exposes the native
tool set through DeerFlow's generic MCP client. ([#4745])
- **community:** Agentic browser control as a first-class thread capability -
Playwright-backed browser sessions the agent operates while the user observes
or takes over from the workspace. ([#4187])
- **community:** Lark/Feishu CLI integration bundles the runtime install, the
official `lark-*` skill pack, and an interactive auth flow so the integration
is no longer environment-dependent. ([#3971])
- **integrations:** Lark/Feishu app credentials can be switched per user
from Settings > Integrations: new App ID/Secret values are validated
before anything is committed, and the previous OAuth token is revoked
after a successful switch. ([#4703])
- **acp:** MiniMax Code (`mcode acp`) is supported and documented as a
native external coding agent, and ACP thought chunks are no longer
concatenated into tool results. ([#4846])
- **models:** A Z.AI GLM-5.3-Flash profile keeps thinking permanently enabled
and stops generic reasoning-effort forwarding, since the model rejects
disabled thinking and only accepts its own effort values. ([#5074])
- **community:** New web search providers - Serply (with news and scholar
verticals) and Tencent Cloud WSA - plus native recency filters
(day/week/month/year) shared across DDGS, Brave, Tavily, and SearXNG.
([#5023], [#5057], [#5099])
- **community:** New Sofya `web_search` and `web_fetch` provider - search
results carry the content of each page, capped per result so a default
search stays inline. ([#5239])
- **knowledge:** Opt-in read-only RAGFlow retrieval exposes a
`knowledge_search(query)` agent tool over configured RAGFlow datasets, with
a dataset-ID allowlist and credential/dataset-id redaction on error paths.
([#4955])
- **knowledge:** Opt-in read-only LightRAG retrieval is an alternative
`knowledge_search(query)` provider for the same `knowledge` group —
operators pick RAGFlow or LightRAG by which entry is configured. It queries
LightRAG's structured `/query/data` endpoint (no LLM generation), formats
the ranked chunks as citation-numbered text, redacts the optional
`X-API-Key` on every model-visible path, and maps server error messages to
actionable tool errors. ([#5209])
#### MCP
- **mcp:** A durable task runtime for MCP: long-running tool tasks survive
Gateway restarts through a durable driver, and their progress and
completion notifications surface in the chat UI. ([#4665], [#4690],
[#4833])
- **mcp:** Shared MCP servers can inject per-user credentials: a single
server entry authenticates each DeerFlow user with their own header
value, unmapped users are denied by default, and stored credentials are
masked in Gateway API responses. ([#4868])
- **mcp:** Per-server `tool_name_prefix` option lets servers that already
namespace their own tools keep their original tool names; the default
behavior is unchanged. ([#4624])
- **mcp:** Settings > Tools can add, edit, and delete MCP servers through
targeted Gateway endpoints, with a copy-paste JSON workflow that preserves
advanced fields and masked secret placeholders. ([#5022])
- **mcp:** Shared HTTP/SSE servers can map request-scoped secrets to headers
via `headers_from_context`: callers supply per-request values in
`config.context.secrets`, the config stores only key names, and missing
values deny by default. ([#5010])
- **mcp:** An optional `parallel-search` server entry
(`https://search.parallel.ai/mcp`, HTTP, no auth by default) ships in
`extensions_config.example.json`, disabled by default; enabling it exposes
`parallel-search_web_search` and `parallel-search_web_fetch`, with optional
Bearer authentication documented. ([#5028])
#### Channels
- **channels:** Expose the IM `channel_user_id` to sandbox commands as
`DEERFLOW_CHANNEL_USER_ID`. ([#3926])
- **channels:** Queue rapid same-thread messages and preserve topic-card
previews across batches. ([#3988])
- **channels:** Inbound webhook deduplication moves to Postgres, so several
Gateway pods can serve the same IM channel without double-processing
events. ([#4210])
- **channels:** DingTalk inbound messages support file and image
attachments. ([#4423])
- **channels:** New Buzz (Nostr) channel connector, including the frontend
experience for the channel. ([#4649], [#4727])
- **channels:** `/agent list` and `/agent use <name>` IM commands let a
conversation switch to the owner's Custom Agents: the selection is
persisted in thread metadata (restored after restart) and wins over stale
channel defaults, IM-created threads route through the same agent when
opened in the web UI, and `/agent` is reserved across the slash-skill
parser, frontend, and TUI so no skill can shadow the command. ([#5168])
#### Auth & guardrails
- **auth:** Generic OIDC/SSO authentication with Keycloak support. ([#3506])
- **guardrails:** Authenticated runtime context is exposed in `GuardrailRequest`,
and security interventions are persisted as run events. ([#3665], [#3837])
- **auth:** "Keep me signed in" login option with a centralized session-cookie
policy (persistent `Secure` cookies on HTTPS, session cookies on public HTTP).
([#4255])
- **auth:** Deployments can close local self-registration to restrict new
accounts to SSO/OIDC provisioning. ([#4311])
- **authz:** Built-in RBAC authorization provider with a unified factory, plus
tool-authorization enforcement at both assembly (tools removed before the
model sees them) and runtime (denied calls blocked). ([#4260], [#4370])
- **authz:** Gateway route permissions are derived from the configured
AuthorizationProvider rather than a fixed table. ([#4439])
- **authz:** Model authorization is enforced at Gateway routes and again in
the agent runtime, and `sandbox:execute` is checked when a sandbox is
acquired - users can no longer reach models or sandboxes they are not
authorized for. ([#4540], [#4911])
- **authz:** `GET /auth/me` now surfaces the caller's effective route
permissions (RFC #4063 Phase 4), read from the `AuthContext` the auth
middleware already stamps on every authenticated request — no extra
provider evaluations — so the frontend can hide actions the caller's role
cannot perform. ([#5228])
#### Sandbox & provisioner
- **sandbox:** New E2B and BoxLite (micro-VM) sandbox providers; BoxLite ships
with a warm pool. ([#3883], [#3940], [#3951])
- **provisioner:** ClusterIP Services and scoped per-skill PVC mounts, plus a
configurable sandbox container port. ([#4016], [#3928])
- **sandbox:** New cloud sandbox providers: Tenki and OpenSandbox.
([#4382], [#4877])
- **sandbox:** An optional lark-cli credential broker sidecar (K8s
provisioner mode) keeps Lark app secrets and OAuth tokens out of the
sandbox filesystem entirely - the sandbox sees only a shim that forwards
commands to a loopback broker in the pod. Off by default. ([#4501])
- **sandbox:** The E2B mount-upload wall-clock deadline is configurable via
`mount_upload_deadline_seconds` (default 120s). ([#4876])
- **sandbox:** An E2B sandbox carries a structured `MountUploadResult`
(`truncated`, `reason`, upload totals) after creation — preserved across
warm-pool reclaim within the process — so mount truncation by a resource
limit is observable in code instead of only in Gateway logs. ([#4884])
- **sandbox:** Opt-in controlled egress for local Docker AIO sandboxes:
`sandbox.network.mode` supports `isolated` (per-sandbox internal bridge
with no outbound route) and `allowlist` (the same bridge plus a
domain-allowlist HTTP(S) policy sidecar that resolves destinations itself
and rejects IP literals and ECH); denied public domains can be approved
through the Human Input card (temporary grant or allow-for-this-sandbox),
non-interactive runs fail closed, and the sandbox API is no longer
published directly in restricted modes. Requires Docker Engine 28+;
`open` remains the default. ([#5152])
#### Extensions & plugins
- **extensions:** An out-of-tree Python extension system: extensions can
contribute middleware, task-lifecycle and system-model observers, Gateway
services, and HTTP routers, and are managed with `deerflow extensions`
install/enable/disable/remove. ([#4636], [#4684], [#4780])
- **extensions:** Extensions can observe what the agent did - message
provenance, middleware policy declarations, agent-assembly fingerprints,
context-compaction records, guardrail decisions, and the MCP origin of a
tool. `deerflow-extension-api` moves to 0.2.0; extensions written against
0.1 are refused at startup with an install hint. ([#4863])
#### Persistence
- **persistence:** A custom PostgreSQL schema can be selected via
`postgres_schema`; ORM, LangGraph checkpointer, and store tables are all
created there, and the schema is created automatically at startup.
([#3442])
#### Frontend
- **frontend:** Branching support for assistant turns and side conversations for
quoted follow-ups. ([#3950], [#3934])
- **frontend:** Regenerate the latest answer. ([#3637])
- **frontend:** Citation-sources evidence panel, workspace change review for
agent runs, and a visualized `ask_clarification` card. ([#3907], [#3945],
[#3956])
- **frontend:** Voice dictation, prompt-history recall with arrow keys, composer
input polishing, and a "(thought for N seconds)" thinking-duration chip.
([#4036], [#3718], [#3986], [#3627])
- **frontend:** Feature-gate the agents UI behind the `agents_api` flag, and
persist AI turn duration in backend and UI. ([#3769], [#3663])
- **frontend:** Render slash-skill activations as inline chips. ([#3981])
- **frontend:** Localized AI-assistance disclaimer. ([#4374])
- **frontend:** Pin recent chats. ([#4442])
- **frontend:** Validate `/goal` objective length in the composer. ([#4337])
- **frontend:** Real-time context window usage is shown as a conversation
grows. ([#3183])
- **frontend:** The latest user turn can be edited and rerun in place.
([#4377])
- **frontend:** Replies can be typed and sent while a clarification card is
pending. ([#4530])
- **suggestions:** The number of follow-up suggestions is configurable via
`suggestions.max_suggestions` (default 3). ([#4533])
- **artifacts:** Text artifacts can be edited inline in the artifact panel.
([#4596])
- **artifacts:** Markdown artifacts open rendered in a new-window reader (with
"View source" and "Download" fallbacks), and all files presented in a run
can be downloaded as one zip archive derived from the run's delivery
receipt. ([#5056], [#5117])
- **frontend:** Browser Live is available in Custom Agent chats. ([#4719])
- **frontend:** A conversation outline navigates long chats: past 5 user turns,
a compact side menu lists the conversation's questions and jumps between
them, tracking the current section. ([#5025])
- **frontend:** Scheduled tasks can be duplicated into an editable draft that
carries over the configuration but not the run history. ([#5064])
- **threads:** Branched conversations get distinguishing titles
(automatic `Title (2)`, `Title (3)` sibling numbering) and the
recent-chats list shows parent-child lineage with tree connectors.
([#4983])
- **frontend:** Chats can be archived and restored: an Archive sidebar
action with an Undo toast, Recent chats / Archived tabs above search, and
per-chat restore controls; SQL and Memory stores apply the archive filter
before pagination while messages, files, links, pin state, and the current
URL are preserved. ([#5236])
- **projects:** Project workspaces organize chats (Projects MVP Phase 1): a
sidebar Projects section with flat/grouped list modes, a project detail
page with a paginated thread list, project-scoped new chats whose threads
are pre-created with their project so a run can never land outside it,
branch membership inheritance, move-between-projects, and project
create/rename/archive/restore/delete. ([#5265])
- **artifacts:** Completed CSV/TSV artifacts preview as bounded tables (up to
200 rows × 50 columns, 50 rows per page, sticky headers, optional
first-row header) parsed off the main thread over the existing 1 MiB
range loader — literal strings, leading zeros, and multiline quoted cells
survive, long cells open in a copyable dialog, and source view remains
one toggle away. ([#5284])
#### Observability & tooling
- **observability:** Trace-id correlation with enhanced logging and agent
observability via Monocle. ([#3902], [#4024])
- **tooling:** A Hermes-like terminal workbench (`deerflow` CLI) backed by
`DeerFlowClient`, plus a redacted community support-bundle generator. ([#3760],
[#3886])
- **setup:** The setup wizard now asks whether OpenAI-compatible gateway models
support thinking, and a Volcengine Coding Plan quick-setup path was added.
([#3428], [#4141])
- **tui:** `clear` command. ([#4306])
- **tui:** The TUI supports a transparent terminal background. ([#4631])
- **gateway:** New `GET /health/ready` readiness probe runs a bounded
database `SELECT 1` and returns 503 while the database is unreachable
(200 `not_configured` for the memory backend); `/health` stays pure
liveness, and the production compose healthcheck now gates on readiness.
([#5166])
- **observability:** Deferred tool promotions — both routing-hint
auto-promotion and explicit `tool_search` — persist as privacy-minimal
`middleware:tool_promotion` run events (tool names, source, count, agent
attribution; no queries, schemas, or results), observed only after
skill-policy filtering so denied schemas are never reported as effective
promotions. ([#5183])
### Changed
- **frontend performance:** Keep the public root and localized docs static;
lazy-load closed workspace panels and editor/highlighter dependencies;
incrementally derive streamed message state; bound streaming Markdown work;
virtualize long message and chat lists; pause offscreen decorative effects;
and enforce representative route JS/CSS budgets.
- **browser:** Negotiate binary Browser Live JPEG frames, retain the legacy
JSON/base64 protocol for older clients, coalesce presentation to the latest
frame per refresh, and revoke replaced object URLs.
- **artifacts:** Stream regular text artifacts with HTTP byte-range support and
limit the initial Web UI preview to 1 MiB until the user explicitly loads the
complete file.
- **sandbox:** The Helm chart now defaults per-sandbox Services to `ClusterIP`
instead of `NodePort`, so the code-execution sandbox is reachable only inside
the cluster via Service DNS (`http://sandbox-<id>-svc.<ns>.svc.cluster.local`)
and is no longer bound on every node's interfaces - including the
externally-reachable ones on GKE/EKS/AKS. Existing chart installs flip
NodePort -> ClusterIP on upgrade. To preserve the old reachability (an
external probe hitting the 30xxx port, or the Docker-Compose/hybrid path
where the gateway is not in K8s), set `provisioner.sandboxServiceType: NodePort`
(with `provisioner.nodeHost` if needed). The provisioner itself is unchanged
(mode-aware since #4016). ([#4190])
- **skills:** An active restrictive skill must explicitly list `task` in
`allowed-tools` to delegate to a subagent. Read-only discovery infrastructure
(`tool_search` and `describe_skill`) remains available, but cannot grant schema
visibility or execution for a denied business tool. ([#4098])
- **memory:** Pre-abstraction top-level `memory.*` DeerMem fields
(`storage_path`, `max_facts`, `debounce_seconds`, `model_name`,
`token_counting`, `staleness_*`, `consolidation_*`, ...) are **auto-migrated
into `backend_config`** on load with a warning, so an upgrade does NOT silently
revert customized settings to defaults (`model_name` ->
`backend_config.model.model`). Move them under `memory.backend_config` in
`config.yaml` to silence the warning. ([#4122])
- **memory:** Added `memory.mode` (`middleware` | `tool`); `tool` mode registers
memory tools (`memory_search`/`add`/`update`/`delete`) the model calls directly
instead of passive per-turn summarization. `manager_class` resolution is now
fail-fast (raises `ValueError` on an unknown backend instead of silently
falling back). ([#4023])
- **middleware:** Declarative layered middleware builder; `ThreadData` now runs
before `Uploads`. ([#3809])
- **sandbox:** The host->virtual output-masking regex now has a single owner,
eliminating duplicated pattern compilation. ([#4108])
- **docs:** `AGENTS.md` is now the source of truth for agent guidance, imported
by `CLAUDE.md` via `@AGENTS.md`; module guides refreshed. ([#3770])
- **memory:** The OpenViking memory backend now uses the official OpenViking
adapter; the old trusted-mode `auth_mode`/`account` fields are rejected in
favor of a credential-bound USER API key. ([#4707])
- **gateway:** Threads created before the run-event journal have their
checkpoint history backfilled as seed events before the first new run, so
legacy conversations stay visible and correctly ordered after an upgrade.
([#4590])
- **agents:** Subagent delegation is now routed by net benefit: the lead agent
defaults to direct execution unless parallel latency, specialist capability,
or context isolation clearly pays off. ([#4384])
### Fixed
- **models:** Stop every Claude model after the first from losing its
credential when the Claude Code OAuth token is handed off through
`CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR`. Every `ClaudeChatModel` instance
loaded credentials again, but a descriptor can be drained only once, so the
title, summarization, and subagent models — and every later run — had no
credential and failed with `TypeError: Could not resolve authentication
method`. The token is now read once per process and reused. ([#5411])
- **models:** Stop the lead agent from failing to build whenever a model with
`supports_reasoning_effort: true` also gets a `reasoning_effort` from its
profile — at the top level, in `when_thinking_enabled` or
`when_thinking_disabled`, or from the `extra_body.thinking` disable path. The
regular lead-agent build forwards the requested effort even when unset, so
the key reached the provider constructor twice and raised `TypeError: got
multiple values for keyword argument 'reasoning_effort'`. The requested value now
layers like per-agent `model_settings`: it replaces a top-level profile
value, an unset request keeps that value, and the thinking-mode settings still
decide the final one. Codex keeps its own level check. ([#5403])
- **runtime:** Stop a keyed run retry from failing with 500 on the SQL run
store. HTTP admissions do not pass a `user_id`; the SQL store stamps the
request user on the row, but the process-local run record kept `None`. A
retry with the same `Idempotency-Key` that reached another Gateway worker, or
the same worker after the finished run was cleaned up, compared the two
owners, took its own run for another user's, and raised. The same mismatch
dropped HTTP runs from owner-scoped history reads and skipped the MCP
`background_tasks` projection for them, so `values` events for these runs now
include `background_tasks`. `RunManager` now resolves an omitted owner from
the request user the way the SQL store does, so every store records the same
owner. ([#5401])
- **runtime:** Stop a cross-worker idempotent run reuse from permanently
blocking the thread on the reusing worker. The reuse registered the hydrated
store row as a local run record, but only the owning worker finalizes and
cleans up its records, so the copy kept its admission-time `pending`/`running`
status forever: every later `reject` admission for that thread on the worker
returned 409 until a restart, its run reads kept reporting the stale status,
and orphan reconciliation skipped the run if the owner crashed. A cancel sent
to that worker also took the local-owner path and marked the owner's
still-running row `interrupted`. The reusing worker now returns a detached
store-only handle instead, so cancel follows the non-owner contract.
([#5393])
- **skills:** Stop writing resolved secrets into `extensions_config.json` when a
skill is toggled. The Gateway skill toggle and `DeerFlowClient.update_skill`
loaded the file through `ExtensionsConfig.from_file()`, which replaces every
`$VAR` value with the environment value, and wrote that model back — so a
`"$GITHUB_TOKEN"` reference was persisted as the plaintext token and an unset
variable was permanently replaced with `""`. `DeerFlowClient.update_mcp_config`
did the same for every key other than `mcpServers`. These writers now edit the
raw on-disk JSON and validate the candidate the way the runtime loads it, so
placeholders and hand-written structure survive; the MCP router shares the same
raw loader. Files rewritten by an earlier toggle keep their plaintext values:
restore the `$VAR` references and rotate the exposed credentials. ([#5357])
- **gateway:** Honor `disable_clarification` and `github_token` only for
internally-authenticated callers, the way `non_interactive` already was.
Both keys were forwarded from `body.context` regardless of the caller and
were not scrubbed from the free-form `body.config` that the run config
copies verbatim, so any session or PAT caller could set them.
`disable_clarification` is the stronger of the two: `ClarificationMiddleware`
answers every clarification — `risk_confirmation` included — with "proceed
without asking", and `SandboxMiddleware` reads it as the same
non-interactive signal as `non_interactive`. `github_token` reached
`runtime.context`, where the bash tool exports it as `GH_TOKEN`/`GITHUB_TOKEN`,
and a copy smuggled through `body.config['configurable']` was persisted in
the checkpoint store. The scheduler, IM channels, and the GitHub webhook
channel authenticate over the internal request channel and are unaffected.
([#5338])
- **artifacts:** Keep `PUT /api/threads/{id}/artifacts/{path}` confined to
`/mnt/user-data/outputs`. The outputs-only guard was a string-prefix check on
the raw path, so a percent-encoded `..` (`outputs/%2e%2e/uploads/x.txt`) —
which nginx forwards untouched and Starlette decodes — passed it, and the
resolver only confines to `user-data/`, letting a caller overwrite a sibling
upload or workspace file in their own thread. Dot segments are now collapsed
before the prefix check, and the resolved host path is re-checked against the
resolved outputs root so a symlink planted inside `outputs/` cannot redirect
the write either. The rule now lives in one shared helper that IM-channel
attachment delivery uses as well, so the two copies cannot drift. ([#5321])
- **gateway:** Stop persisting a caller-supplied `deerflow_trace_id` on the run
record. `body.metadata` reaches both the live run config, which the run
worker restamps, and the run record echoed verbatim by the runs API; only the
first was covered, so a client could make the most durable surface of a run
disagree with the `X-Trace-Id` and the log lines from the same request. The
id is now stamped once at the trust boundary, `config.context` is closed off
the same way, and a thread's own metadata is no longer seeded with the
run-scoped id of whichever run created it. ([#5119])
- **gateway:** Expose `X-Trace-Id` in `Access-Control-Expose-Headers`. It is not
CORS-safelisted, so split-origin browser clients — the ones that cannot read
the Gateway's logs either — could not read the correlation id they are meant
to quote in a bug report. ([#5119])
- **gateway:** Keep `X-Trace-Id` on unhandled-exception 500s. Starlette's
`ServerErrorMiddleware` emits those through the raw send outside every user
middleware, so the 500 for a server bug — the response most in need of
correlation — was the only one shipped without the id. `TraceMiddleware` now
sends its own 500 carrying the header before re-raising; the server's
exception logging is untouched and mid-stream failures propagate unchanged.
This fallback is emitted outside `CORSMiddleware` and stays CORS-opaque, so
split-origin browser clients cannot read the id on this one response — same
as the `ServerErrorMiddleware` 500 it replaces. ([#5119])
- **gateway:** Strip a forged `deerflow_trace_id` from the persisted request
echo. `body.config` is stored verbatim as `runs.kwargs_json` and served back
by the runs API, so a forged id in `config.metadata` or `config.context`
survived on that one surface while every other carried the real id.
`redact_config_secrets` now drops the key from both containers, and
`build_run_config` merges run metadata onto a copy so the server-stamped id
can no longer be written through into the caller's request body. ([#5119])
- **artifacts:** Keep explicit full-file loading scoped to the source thread, so a same-path artifact in another conversation keeps its 1 MiB preview. ([#4634])
- **sandbox:** `SandboxAuditMiddleware` no longer blocks ordinary command
substitution that only captures output. The rule now judges *position* instead
of matching any `$(`: `x=$(curl url)`, `echo $(curl url)`, an argument, and a
`for` word list all run normally, while a substitution in command position
(`$(curl url)`, after a `|`/`&&`/`;`, behind leading assignments or an
`env`/`nohup`/`time` style wrapper, or as an `eval`/`source` argument) still
blocks because it executes fetched content. An interpreter's code-string flag
(`bash -c`, `python -c`, `perl -e`, `node -p`, `php -r`, and the `<<<`
here-string) is treated as an execution context wherever it appears, so
`bash -c "$(curl url)"` blocks; `source <(curl url)` and the backtick spelling
of `eval`/`source` now block too, neither of which was detected before. An
unquoted newline separates statements like `;`, so `echo hi` followed by a
new line starting `$(curl url)` blocks as well, while heredoc bodies are
consumed as data — writing a file whose content happens to start a line with
`$(curl url)` is not a command.
Variable expansions whose name merely starts with a risky executable
(`$shell`, `$bashrc`, `$python_version`) and lookalike binaries
(`shellcheck`, `shasum`) are no longer false positives.
([#4611], [#4623])
- **mcp:** Isolate Settings > Tools enable/disable updates to one MCP server, so
an unrelated disallowed stdio command no longer blocks every switch; allow
disabling a disallowed target while still rejecting its re-enable, preserve
the raw extensions config, honor the MCP-spec `transport` alias when enabling
SSE/HTTP servers, surface backend validation details in the UI, and atomically
replace the shared config for MCP, skill, and embedded-client updates so
interrupted writes cannot leave it truncated.
([#4574], [#4577])
- **runtime:** Thread metadata now switches to `running` only after the run passes
the startup barrier, so pending-cancelled runs no longer briefly project
`running`; clients may observe the prior thread status during worker startup.
([#4450])
- **runtime:** Re-check orphan candidates through an atomic, lease-aware takeover
claim so a successful heartbeat after the scan keeps the run active and only
one reconciler reports recovery. ([#4424], [#4434])
- **skills:** Apply `allowed-tools` only to slash-activated or actually loaded
lead-agent skills, preventing passive enabled skills and evaluation fixtures
from removing MCP, web, file, and delegation tools from every run. ([#4095],
[#4098], [#4192])
- **models:** Honor `api_base` on every `BaseChatOpenAI` subclass (`VllmChatModel`,
`MindIEChatModel`, `PatchedChatMiMo`, `PatchedChatStepFun`, `PatchedChatMiniMax`),
not just `ChatOpenAI` / `PatchedChatOpenAI`. Those five previously dropped the
configured endpoint silently and then failed every request with an opaque
`unexpected keyword argument 'api_base'`; the unknown-config-key warning was
disabled for them as well. Both now gate on `issubclass(BaseChatOpenAI)`.
([#4146])
- **agents:** Coalesce `SystemMessage`s before the LLM request; ensure a visible
response after tool runs; avoid a default LLM title call before stream end;
reserve ellipsis room so the local title respects `max_chars`; and snap the
tool-output tail forward so fallback truncation respects `max_chars`. ([#3711],
[#4033], [#3885], [#4052], [#4017])
- **agents:** Skip dateless reminders in the dynamic-context date scan; load
`SOUL.md` from agent dirs without `config.yaml`; require `config.yaml` in
`update_agent`'s legacy-agent guard; and refuse empty `SOUL.md` updates.
([#3685], [#4136], [#4166], [#4219])
- **middleware:** Window the loop-detection tool-frequency counter so long runs
no longer false-trip; prevent the title middleware from streaming tokens;
fix positional fallback consuming an unrelated todo when the same-content list
is exhausted; acquire the token-budget lock across `_apply`, `before_agent`,
`_clear_run_state`, and `_drain_pending_warnings`; drop orphan `ToolMessage`s
so strict providers don't 400; sanitize invalid tool-call arguments; and
recover from empty tool-call names and malformed tool-call ids in dangling
repair. ([#4072], [#3566], [#3709], [#3714], [#4080], [#4193], [#4008],
[#4246])
- **subagents:** Inherit `LoopDetectionMiddleware` and summarization middleware
so tool loops break and steps are captured; surface the turn-budget cap as
`MAX_TURNS_REACHED` with a partial result; unify guardrail caps on the additive
`stop_reason` + `token_budget`; inject durable context before compaction;
preserve the parent checkpoint namespace; prohibit the `task` tool in the
general-purpose system prompt; re-buffer subagent events on flush failure to
avoid losing steps; and fix the lost `loop_capped` stop reason when a
subagent's `run_id` is `None`. ([#3931], [#4009], [#3949], [#3980], [#4040],
[#4215], [#4161], [#4082], [#4059])
- **memory:** Harden against null/empty edge cases - skip whitespace-only facts;
coerce null `confidence` / `source.confidence` in updates, searches, and the
three remaining raw reads; treat explicit `null` `backend_config` values as
omitted; fix `KeyError` / `UnboundLocalError` when a fact has no id or the
facts list is empty; stop the busy-spin in the debounced update queue; and
flush the memory queue on graceful shutdown to prevent loss. ([#3719], [#4074],
[#4076], [#4034], [#4217], [#3993], [#3992], [#4073], [#4181])
- **runs:** Close multi-worker ownership gaps in run atomicity; fail-stop local
execution when lease renewal cannot be confirmed before its deadline and
fence late completion writes after peer takeover; degrade cancel to lease
takeover for multi-worker; keep `create_thread` idempotent when the insert
loses a race; read `stop_reason` from runtime context; and persist run duration
in checkpoints for history reads. ([#4003], [#4064], [#4414], [#3800], [#4188],
[#4118], [#4431])
- **runtime:** Serialize SQLite event-store writes to prevent per-thread
sequence collisions; skip hidden human messages in the journal; and drop the
silent delta-discard in `_merge_stream_text`. ([#4077], [#3698], [#4085])
- **gateway:** Attach thread-message feedback by real `event_type`; offload
blocking filesystem IO in artifact serving, gateway uploads, and the Discord
channel; limit the uploaded-file context manifest; and live-tail malformed
Redis reconnect ids. ([#3651], [#3551], [#3935], [#3927], [#3917], [#4012])
- **uploads:** Claim the converted-Markdown companion filename before writing
it, so two convertible uploads sharing a stem (or a convertible plus a
same-stem `.md` upload) no longer silently clobber each other within one
request. When `uploads.auto_convert_documents` is on, the companion `.md` now
gets a unique name (e.g. `a_1.md`); `POST /threads/{id}/uploads` and
`DeerFlowClient.upload_files` both report the actual name in `markdown_file`.
([#4288])
- **config:** Coerce null object config sections to their defaults; honor the
unified database configuration in the store and sync checkpointer; and have
legacy DB backfill create missing `Index` objects on existing tables. ([#3573],
[#3904], [#3994], [#4090])
- **models:** Apply the `stream_chunk_timeout` default to all `BaseChatOpenAI`
subclasses; and normalize `api_base` -> `base_url` for `ChatOpenAI` with a
warning on unknown config keys. ([#4102], [#3790])
- **mcp:** Isolate tool-discovery failures per server; synchronize the
session-pool singleton lifecycle; invalidate the tools cache on config content
+ path (not just newer mtime); validate MCP tool names at load so deferred
prompts stay inert; and route tools by source server, not name prefix. ([#3772],
[#3797], [#4124], [#4154], [#3812])
- **skills:** Activate a slash skill once per run, not per model call; close the
skill-install security-scan coverage gap; recognize fully deleted skill
packages in review CI and remaining `requests` / `httpx` methods as network
sinks in SkillScan; reuse the resolved app config in the no-arg skills prompt
section; and reload mounted skills without restarting the Gateway. ([#4103],
[#3924], [#4169], [#4130], [#4160], [#4264])
- **sandbox:** Guard the reverse path-translation and output-masking regexes
with segment boundaries; handle one-sided line ranges and empty files in
`read_file` / `str_replace`; align the AIO bash working directory; use
`os.sep` in the reverse-resolve containment check on Windows; normalize
Windows backslash paths in bash commands; stop `glob` / `grep` / `ls` from
surfacing disabled skills' files; and allow valid heredoc commands in the
sandbox audit. ([#4035], [#4053], [#4078], [#4079], [#4051], [#4058], [#3869],
[#4096], [#3786])
- **sandbox:** Synchronize the sandbox provider singleton lifecycle (with
concurrency regression tests) and keep k8s calls off the event loop in the
provisioner. ([#3730], [#3941])
- **sandbox:** Align sandbox artifact mounts with the channel user; fix
local-dev (`make dev`) on non-root / NFS hosts; reap macOS nginx processes on
stop; and fix production Postgres UV-extras detection in Docker. ([#3729],
[#3590], [#3828], [#3897])
- **channels:** Validate the channel provider before resolving its config;
dedupe GitHub webhook redeliveries and drop redundant GitHub review-comment
webhook fan-out; scope the slash-skill whitelist check to the run's owner;
batch Feishu file messages into one thread and dispatch Feishu group commands
prefixed with a bot @mention; accept leading @mentions before `/connect` bind
codes and don't treat a bare "connect" as a bind command; stop Feishu from
creating thread topics and throttle card updates; let the UI runtime channel
config win over `config.yaml`; fix `require_mention` gating on
whitespace-only `bot_login` / `mention_login`; guard null quote fields in
WeCom; and key inbound dedupe on chat-scoped workspaces so Telegram, Feishu,
WeChat and DingTalk redeliveries stop re-running the agent on a default
(unbound) configuration, releasing the dedupe key on transient failures so a
redelivery can still recover. ([#4100], [#4104], [#4131], [#4129], [#3753],
[#4229], [#4222], [#4251], [#3810], [#3674], [#4055], [#4069], [#4287])
- **frontend:** Preserve messages and durable context across summarization;
preserve artifacts and stabilize artifact paths during streaming; resolve
relative artifact image paths; retain presented artifacts in the header
dropdown; keep orphan tool messages visible; show assistant text during tool
steps; reset new chat on client-side navigation; prevent stream cancellation
on concurrent submit; fix stale-run reconnect and cancel handling; fix chat
math rendering, single-tilde markdown, double reasoning rendering, UTF-16
markdown binary classification, and `<memory>` tags in Streamdown; make
recent-chat rows fully clickable; validate attachment limits before upload and
fix uploaded-file metadata in message copy; fix mobile workspace and
accessibility blockers, the card tool-message bug, and side-chat toolbar /
panel-button behavior; block unresolved suggestion-template placeholders;
refresh notification permissions; show the branch action only for completed
turns; enable regenerate in custom agent chats; and generate a fallback title
for interrupted first-turn runs. ([#3826], [#3791], [#4094], [#4038], [#3854],
[#3880], [#4114], [#3673], [#3878], [#3908], [#3557], [#4245], [#3870], [#3966],
[#4209], [#3733], [#3900], [#3944], [#3740], [#3976], [#3959], [#3961], [#3764],
[#3768], [#4147], [#3967], [#3874], [#3644])
- **tui:** Interrupt an active run before `/quit` exits. ([#4235])
- **harness:** Don't flag the outline as truncated at exactly `MAX_OUTLINE_ENTRIES`
headings. ([#3856])
- **tracing:** Attach Langfuse trace metadata to the goal evaluator. ([#4202])
- **context:** Resolve the context-compress bug. ([#4065])
- **threaddata:** Fix `AttributeError` when `runtime.context` is `None`. ([#3989])
- **goal:** Stop `continuation_count` double-bump during stand-down. ([#4199])
- **circuit-breaker:** Stop wedging after a non-retriable half-open probe. ([#3991])
- **github:** Match `allow_authors` logins case-insensitively. ([#4218])
- **community:** `image_search` now returns the full-resolution image URL. ([#3990])
- **skills:** Offload blocking filesystem IO in the skill-history endpoint.
([#3563])
- **skills:** Don't treat a lazily evaluated PEP 695 type alias as a network
sink in SkillScan. ([#4315])
- **tracing:** Resolve the Langfuse trace user from runtime context. ([#3794])
- **guardrails:** Propagate internal owner attribution into the guardrail
context. ([#3839])
- **subagents:** Clamp the subagent limit consistently with
`MIN_SUBAGENT_LIMIT`. ([#4081])
- **subagents:** Load user-scoped skills. ([#4356])
- **mcp:** Per-server fail-soft OAuth priming, and persist rotated refresh
tokens. ([#4084])
- **mcp:** Ignore malformed path-like text. ([#4456])
- **auth:** Resolve email accounts case-insensitively. ([#4101])
- **auth:** Recover from setup-status timeouts. ([#4371])
- **scheduler:** Close a dispatch race that could launch two runs for one
scheduled task. ([#4105])
- **channels:** Buffer and drain GitHub comments queued during a busy run.
([#4133])
- **channels:** Escape Slack reserved characters before mrkdwn conversion.
([#4197])
- **channels:** Check `response.success()` on Feishu card/reaction SDK calls.
([#4234])
- **channels:** Drop inbound DingTalk messages that carry no conversation
identity. ([#4316])
- **channels:** Receive inbound Telegram attachments. ([#4392])
- **memory:** Consolidated facts inherit `expected_valid_days` from their
sources. ([#4225])
- **config:** Sync `_memory_config` with AppConfig auto-reload. ([#4208])
- **postgres:** Harden the async engine with `pool_recycle` and
`command_timeout` to stop stale-connection 504s. ([#4230])
- **harness:** Add a timeout to `invoke_acp_agent` to prevent indefinite hangs.
([#4238])
- **community:** Surface the target-page error status in `web_fetch`
(Browserless). ([#4239])
- **sandbox:** Widen the BoxLite/AIO tenant hash and verify identity on reclaim.
([#4171])
- **sandbox:** Make an empty `old_str` a no-op in `str_replace` on any file.
([#4256])
- **sandbox:** Serialize E2B release transitions. ([#4355])
- **sandbox:** Bound E2B output-synchronization resources. ([#4364])
- **sandbox:** Unwrap `Overwrite`-wrapped sandbox state in `after_agent`.
([#4381])
- **sandbox:** Bypass proxies for local AIO traffic. ([#4444])
- **models:** Surface length-capped model responses instead of dropping them.
([#4309])
- **streaming:** Keep large file generation responsive. ([#4354])
- **streaming:** Expose custom events to `astream_events`. ([#4403])
- **streaming:** Signal replay history gaps. ([#4426])
- **summarization:** Summarize with the run model and fall back on
summary-provider failure. ([#4361])
- **runtime:** Remove transient image context after model calls. ([#4267])
- **runtime:** Stop subgraph stream frames from impersonating root frames.
([#4407])
- **runtime:** Reject unsupported run options and stream modes. ([#4430])
- **runtime:** Serialize checkpoint writes with active runs, linearize
delta-mode checkpoint resume, and accept the SDK's default
`stream_resumable=false` to avoid resume races. ([#4437], [#4460], [#4468])
- **checkpoint:** Unwrap `Overwrite` first writes into empty channels. ([#4383])
- **nginx:** Allow long chat prompts through `/api/langgraph/` without a raw
500. ([#4277])
- **gateway:** Prefer `X-Trace-Id` over `metadata.deerflow_trace_id` when the
header is set. ([#4283])
- **gateway:** Seed branch run-events so inherited history survives forking.
([#4385])
- **gateway:** Scope branch-history seed run ids per inherited turn. ([#4459])
- **frontend:** Harden artifact and markdown rendering. ([#4117])
- **frontend:** Classify a symlink replacing a file distinctly from deleted in
workspace-change review. ([#4170])
- **frontend:** Offload blocking filesystem IO in the workspace-change
text-cache lifecycle. ([#4268])
- **frontend:** Encode artifact URL path segments. ([#4278])
- **frontend:** Clarify run-duration display. ([#4348])
- **frontend:** Preserve regenerate state in branched threads. ([#4358])
- **frontend:** Default the reasoning-effort label to Medium when unset.
([#4373])
- **frontend:** Strip and parse the `<current_uploads>` upload-context tag.
([#4402])
- **frontend:** Keep leading orphan tool messages visible. ([#4408])
- **frontend:** Keep completed subtask cards stable after reload. ([#4432])
- **frontend:** Apply message-image `maxWidth` via inline style. ([#4446])
- **frontend:** Restore resizing for the artifacts and sidecar panels. ([#4469])
- **frontend:** Allow dev-server access from non-localhost hosts. ([#4471])
- **safety:** Backfill empty content-filter responses so they don't poison the
thread. ([#4394])
- **tools:** Exclude injected runtime from the `list_uploaded_files` schema.
([#4376])
- **mcp:** Bound MCP server bring-up — tool discovery (subprocess spawn +
`initialize` + `tools/list`) and persistent stdio session initialization —
with a new per-server `session_init_timeout` (default 60s, `null` disables),
so a hung stdio server can no longer block agent construction, or the whole
Gateway event loop, indefinitely. `tool_call_timeout` still bounds individual
stdio tool calls. ([#4657])
- **runtime:** Tool-output budget externalization no longer trips run delivery
verification. The default `.tool-results` storage dir (and any custom
`tool_output.storage_subdir`) is excluded from workspace-change snapshots and
produced-artifact detection, so a run that only externalized oversized tool
outputs succeeds instead of failing as an error. ([#4657])
- **frontend:** Hide stale follow-up suggestion chips while a turn is still
streaming. ([#3396])
- **frontend:** Fix streaming render glitches: stop the word animation from
replaying, keep step text stable, preserve message order during long runs,
and keep reasoning above the answer. ([#4266], [#4510], [#4513], [#4578])
- **frontend:** Encode thread IDs in chat routes so IDs with special
characters no longer break navigation. ([#4302])
- **frontend:** Render citation links from React children. ([#4486])
- **frontend:** Localize conversation export failure messages. ([#4493])
- **frontend:** Sync side panel state when a drag collapses the panel. ([#4556])
- **frontend:** Render one workspace-change card per run instead of
duplicates. ([#4559])
- **frontend:** Refresh the active artifact's content when it changes. ([#4584])
- **gateway:** Reject non-positive read limits in API requests. ([#4284])
- **gateway:** Handle a null `config.configurable` when resolving the thread
id instead of failing. ([#4301])
- **gateway:** Unify thread id validation across API routes. ([#4589])
- **gateway:** Merge concurrent thread metadata updates instead of letting
them silently overwrite each other's changes. ([#4489])
- **gateway:** Expose the run metadata response header to cross-origin
clients, so a split-origin frontend learns new run ids instead of staying
stuck on the new-thread placeholder route until reload. ([#4535])
- **gateway:** Replay edit and rerun from a settled checkpoint so the edited
prompt actually runs (previously a first turn's edit replayed the original
prompt and vanished after reload), and keep a manual rename through the
rerun. ([#4534], [#4539])
- **runtime:** Cancel a run from any live gateway worker, not only the one
that owns it, so the stop button no longer depends on request routing.
([#4500])
- **runtime:** Close a replacement run when interrupt or rollback admission
is cancelled mid-flight, instead of stranding an unseen active run on the
thread. ([#4472])
- **runtime:** Regenerating a response now preserves the thread's current
title and supports the latest interrupted response whose partial message
never reached a checkpoint. ([#4480], [#4524])
- **agents:** Classify web_fetch error pages such as 404s as errors rather
than successful evidence, so retries and stagnation guards can react.
([#4314])
- **agents:** Handle XML-to-dict option shapes when normalizing
clarification choices. ([#4527])
- **subagents:** Run delegated subagents with isolated callbacks and lazy
skill activation, fixing cross-event-loop failures and passive skills
stripping baseline tools like `write_file`. ([#4497])
- **sandbox:** Handle overwrite-wrapped state when ensuring the sandbox is
initialized. ([#4429])
- **sandbox:** Reconcile E2B sandboxes safely: pick the first healthy
candidate, adopt the canonical instance per user and thread, defer a
peer's live duplicates, and reap orphans after a grace window. ([#4443])
- **sandbox:** Claim ownership before destroying a sandbox that failed its
readiness check, so a peer gateway can no longer adopt the not-yet-ready
sandbox and kill a live turn. ([#4505])
- **sandbox:** Allow grep to search a single file. ([#4512])
- **sandbox:** Enforce the E2B capacity limit deployment-wide when sandbox
ownership uses Redis, so multiple gateways cannot create past it. ([#4575])
- **skills:** Activate managed integration skills from the managed
integrations root on slash invocation. ([#4570])
- **skills:** Offload blocking filesystem IO when updating a skill and
serialize concurrent writes. ([#3565])
- **mcp:** Ignore oversized path-like text. ([#4582])
- **memory:** Harden long-term memory: reject duplicate facts inside the
create critical section, truncate injected mem0 context on entry
boundaries, and keep task-scoped instructions such as "inspect only" out
of long-term memory. ([#4599], [#4600], [#4604])
- **scheduler:** Keep a successfully launched scheduled run's slot and run
id when post-launch bookkeeping fails, preventing a later dispatch from
launching a duplicate run. ([#4504])
- **config:** Treat a deleted extensions config file as absent instead of
raising, so tool and skill config resolution keeps working. ([#4275])
- **config:** Normalize the `postgres://` short scheme for the async ORM
engine. ([#4293])
- **console:** Disable cost reporting when model pricing mixes currencies
instead of reporting a meaningless cross-currency total. ([#4564])
- **browserless:** Accept the `timeout` config key and harden its coercion.
([#4519])
- **docker:** Send `Connection: upgrade` only when the browser requests it,
fixing login-page refresh loops when the Docker dev stack is accessed via
a remote host. ([#4250])
- **runtime:** Group JSONL batch event writes by run, so a batch covering
several runs no longer lands all events in the first run's file and makes
later runs unreadable through per-run APIs. ([#4938])
- **runtime:** Restore standalone LangGraph Studio compatibility: the graph
entrypoint and file-based app load again, the Studio identity can discover
system assistants, and the documented `langgraph dev` workflow works.
([#4760], [#4838])
- **gateway:** Stamp `turn_duration` on a run's last AI message only in
`/messages/page`, so multi-step turns no longer repeat the same run
lifetime as thinking latency on every intermediate message. ([#4755])
- **gateway:** Preserve exact history attribution beyond the event page
limit, so older AI messages on long-lived threads are no longer credited
to a later turn's run and duration. ([#4953])
- **gateway:** Reject MCP task cancellation with HTTP 503 when the task
worker is stopped, instead of acknowledging a cancellation that would
never run. ([#4963])
- **middleware:** Correct four context-handling defects: fallback
dynamic-context injection targets the latest user message instead of
resurrecting an old prompt as the current turn; bare string blocks in
list-form user content are sanitized like all other user text; duplicate
placeholders are no longer emitted for the same invalid tool call; and
summarization no longer compresses away the current request's user message
while leaving the previous turn's behind. ([#4667], [#4668], [#4693],
[#4882])
- **middleware:** Restore the system-prompt injection that teaches the model
about the `write_todos` tool, which the todo middleware's model-call
override had silently dropped. ([#4735])
- **agents:** Make SQL agent-store signatures content-sensitive, so an agent
update that reuses its previous timestamp no longer leaves the GitHub
agent registry serving stale webhook routing. ([#4709])
- **tools:** Resolve presented files with the runtime user, so `present_files`
no longer rejects valid artifacts as outside the outputs directory when
the request user context is unavailable. ([#4677])
- **tools:** Retain a strong reference to deferred subagent cleanup tasks, so
garbage collection can no longer destroy a pending cleanup and leak
cancelled subagent records, locks, and memory. ([#4928])
- **subagents:** Give every background subagent run a server-side execution
ID, so concurrent runs that reuse a provider tool-call ID can no longer
overwrite, poll, or cancel each other's state. ([#4758])
- **harness:** Offload ACP workspace creation and MCP config loading from the
event loop, so invoking an ACP agent no longer raises blocking-IO errors
or stalls other async work. ([#4965])
- **mcp:** Reject non-finite `poll_after_seconds` values on task snapshots
when they arrive, so a bad polling interval no longer crashes scheduling
and persistence after a successful poll. ([#4750])
- **mcp:** Keep the configured `grant_type` authoritative over
`extra_token_params` during OAuth token exchange, so extra parameters can
no longer silently switch the configured flow and be rejected by the token
endpoint. ([#4860])
- **mcp:** Exclude the internal stdio MCP temp directory (`.mcp/tmp`) from
workspace changes, so MCP temporary and debug files no longer appear
alongside user deliverables or crowd real changes out of the file budget.
([#4898])
- **mcp:** Cancel the remote task when a durable task submission is cancelled
mid-flight, so an interrupted submission no longer leaves a remote task
running with no record to poll or stop. ([#4933])
- **sandbox:** Accept the documented E2B reconciliation config fields, so
valid E2B configuration no longer produces misleading startup warnings.
([#4772])
- **sandbox:** Bound E2B mount upload resource use per file, per mount, and
across the whole upload pass (shared size and file budgets plus a
wall-clock deadline), so large mounts can no longer spike Gateway memory
or hold sandbox capacity indefinitely. ([#4812], [#4842])
- **sandbox:** Preserve trailing whitespace in E2B-synced filenames and
tolerate out-of-range remote mtimes, so output sync no longer re-downloads
files repeatedly or aborts mid-sync. ([#4861])
- **sandbox:** Reject non-finite Redis lease-timing values in sandbox
ownership config at parse time instead of crashing with an `OverflowError`
during startup. ([#4960])
- **sandbox:** Resolve structured skill reads through the sandbox provider's
path mappings, so `read_file` opens legacy and per-user custom skills
under the same enabled-state projection as `ls` and shell execution.
([#4792])
- **skills:** Parse Responses API content blocks in the moderation scanner,
so valid skill-management decisions returned as content blocks are no
longer rejected as unparseable. ([#4936])
- **memory:** Reject non-positive and non-finite timeout and character-limit
settings in the Honcho and Mem0 backends at config parse time, so a bad
value fails fast instead of silently truncating stored text or crashing on
the first HTTP call. ([#4783], [#4823])
- **memory:** Scope custom-agent bootstrap facts to the selected agent's
bucket, so facts learned during setup no longer leak into the default
bucket and influence ordinary lead-agent conversations. ([#4804])
- **artifacts:** Support atomic saves on Windows, and serve a SHA-256 ETag on
artifact reads so inline preview and editing work on non-secure contexts
such as plain-HTTP LAN origins where `crypto.subtle` is unavailable.
([#4629], [#4865])
- **frontend:** Keep conversation order stable around long runs: the
submitted user message no longer renders twice or sinks below its own
processing steps, and after a mid-run page reload a turn's steps can no
longer appear above the user message that started the run. ([#4620],
[#4660], [#4834])
- **frontend:** Stop matching `<header>` as `<head>` when injecting the base
href into HTML artifact previews, so relative assets in report fragments
that begin with `<header>` now load in the sandboxed preview iframe.
([#4625])
- **frontend:** Open landing-page case studies on a public read-only
`/showcase/` route so anonymous visitors are no longer redirected to
login. ([#4635])
- **frontend:** Sort the chats page by pinned state, so pinned threads no
longer render below unpinned ones. ([#4643])
- **frontend:** Keep `<think>` pairs written inside markdown inline code in
the rendered content instead of hollowing them out into the Reasoning
panel, and restore the copy button for turns that contain only reasoning.
([#4647])
- **frontend:** Surface model-loading failures with a workspace error banner
and retry action instead of a silently empty model list. ([#4840], [#5021])
- **frontend:** Preserve copy and other actions on completed assistant
messages while a later turn is still streaming. ([#4844])
- **frontend:** Keep the browser live stream connected after a successful
reconnect instead of tearing down the new socket and immediately creating
another. ([#4951])
- **frontend:** Reuse the shared clipboard fallback when copying the Lark
authorization link, so the copy action works in browsers without the
Clipboard API. ([#4767])
- **frontend:** Use consistent "DeerFlow" casing in the composer disclaimer
and fix the "What's New" heading on the landing page. ([#4970])
- **channels:** Bound inbound intake with a fixed worker pool and bounded
admission queues, and await real cross-thread tasks on shutdown, so
message floods are rejected promptly instead of accumulating and channel
shutdown no longer tears down transports with work still in flight.
([#4800], [#4816])
- **channels:** Offload outbound attachment file IO for Feishu, Telegram, and
WeCom to worker threads, so sending a large artifact no longer stalls the
Gateway event loop. ([#4633])
- **channels:** Run Telegram connection-identity lookups on the Gateway event
loop, so inbound messages and commands no longer crash with a cross-loop
error when channel connections are enabled. ([#4815])
- **feishu:** Keep file receiving off the event loop and preserve every
inbound attachment: duplicate provider filenames no longer overwrite each
other, writes can no longer be redirected outside the thread bucket, and a
failed attachment no longer blocks the rest of the message. ([#4627],
[#4903])
- **dingtalk:** Strip leading `@bot` mentions before command classification,
so slash commands like `/new` sent in group chats are recognized instead
of treated as plain chat. ([#4724])
- **discord:** Refuse to start typing-indicator loops after the channel
stops, so shutdown no longer leaves an infinite typing task sending
events in the background. ([#4752])
- **wecom:** Serialize WebSocket start/stop transitions and await the SDK's
real receive-task shutdown, so stopping the WeCom channel can no longer
return before the socket closes or clear a newer connection's state.
([#4762])
- **buzz:** Drop replayed events across reconnects using a persistent
seen-id store, so the agent no longer re-answers the last message in a
channel after a relay or Gateway restart. ([#4888])
- **lark:** Keep the CLI lock directory writable inside sandboxes while the
credential-bearing config root stays read-only, restoring Lark API
commands that previously failed with a read-only filesystem error.
([#4701])
- **scheduler:** Enforce the global `max_concurrent_runs` budget for manual
triggers too, returning HTTP 409 when the cap is reached instead of
letting manual launches exceed it. ([#4769])
- **scheduler:** Coerce serialized task timestamps on read, so
scheduled-task operations no longer fail when string-form timestamp values
reach the database layer. ([#4785])
- **scheduler:** Support safe multi-instance scheduler recovery: startup no
longer treats live runs owned by peer Gateway instances as local
leftovers, so a restarting instance cannot interrupt a live run or trigger
a duplicate execution; multi-instance mode is opt-in via
`scheduler.multi_instance`. ([#4713])
- **scheduler:** Enqueue busy scheduled task runs instead of skipping them:
occurrences that hit a busy reused thread now wait in a durable queue
(bounded by `scheduler.queue_timeout_seconds`) and survive Gateway
restarts, and the UI explains the queueing behavior. ([#4918])
- **cli:** Add `--recursion-limit` to headless `--print`, `--json`, and
`--cli` runs, so long-running agent loops are no longer stuck at the
default recursion limit of 100. ([#4615])
- **dev:** Exclude backend runtime state from the Uvicorn reload watcher in
the backend `make dev` launcher, so an agent task writing files under the
runtime tree can no longer restart the Gateway and reset concurrent
users' requests. ([#4759])
- **dev:** Resolve diagnostic script paths from the script's own location, so
root diagnostic commands work when invoked from any working directory.
([#4736])
- **docker:** Harden local and container startup: `make up` waits for the
Gateway health probe before declaring the stack ready, Docker startup no
longer aborts when `.env` is missing, the Gateway can write
`extensions_config.json` in production, runtime data stays out of the
image build context, log commands resolve the checkout root correctly,
and the default loopback origins are allowed so the dev setup page can
hydrate. ([#4658], [#4806], [#4852], [#4853], [#4956], [#4959])
- **gateway:** Stamp the server-authoritative feed position onto persisted
messages, so an early user message no longer vanishes or jumps into the
middle of the step stream once history exceeds one page and context
compaction has fired. ([#4696])
- **lark:** Preserve the new app secret during managed credential switches by
clearing the previous app's OAuth data before the replacement is written,
so the subsequent browser authorization no longer resolves an empty
`client_secret`. ([#4820])
- **messages:** Drop legacy `<uploaded_files>` tag handling: the backend treats
the pre-#4174 spelling as ordinary content and strips only
`<current_uploads>`, while the frontend keeps stripping the legacy tag so
old threads still render cleanly. ([#4826])
- **skills:** Reject a blank `SKILL.md` description at the write gate, matching
what the loader already requires, so editing a custom skill with an empty
description no longer writes a file the loader then rejects - which
destroyed the skill on disk. ([#4867])
- **sandbox:** Make the model-facing `description` argument optional (empty by
default) across `bash`, `ls`, `glob`, `grep`, `read_file`, `write_file`,
`str_replace`, and `task`, so providers that omit it are no longer rejected
before execution. ([#4878])
- **sandbox:** Bound Windows command execution: host commands run in a new
process group killed via `taskkill /T /F` on timeout so a descendant cannot
hold the call open, and output flows through the existing bounded 10 MiB
capture. ([#4946])
- **sandbox:** Scope the Windows MSYS path-conversion exclusion to safe virtual
path prefixes instead of disabling conversion globally, so host-native CLI
launchers that need normal conversion work again. ([#5003])
- **skills:** Rebuild per-user skill storage after an app-config hot reload,
so it no longer stays bound to paths from the previous config instance.
([#4972])
- **skills:** Tokenize portable `allowed-tools` scalars with parenthesis
awareness, so `Bash(tvly *)`-style entries stay intact, unmatched
parentheses are rejected instead of silently fragmenting, and
argument-scoped entries remain literal rather than broadening access.
([#4984])
- **agents:** Normalize `ToolMessage`s returned inside `Command` results, so
error payloads no longer earn a default success receipt and tool-progress
tracking sees them. ([#4977])
- **mcp:** Tear down the in-flight session owner when `get_session` is
cancelled during eviction, so a cancelled caller no longer leaks the owner
task or parks past its timeout. ([#5008])
- **mcp:** Reconnect ordinary stdio tools after a transport disconnect: the
failed pooled session is evicted (only if still registered), the original
error surfaces without automatic replay, and a later retry starts a fresh
subprocess. ([#5018])
- **mcp:** Preserve pooled stdio sessions after protocol timeouts during
durable MCP task polling - a 408 is not a disconnect - so task state
survives and the next poll no longer reports `task_not_found`. ([#5027])
- **mcp:** Reject credentials that cannot travel as HTTP header values
(trailing newline or whitespace, non-ASCII) at the config boundary, so the
transport's exception - which echoes the full value - can no longer leak a
secret into model context, checkpoints, and traces. ([#5066])
- **subagents:** Clean up the background-task entry when the poller exits
unexpectedly and drop a PENDING registry entry when submission fails, so a
failed or crashed poll no longer leaks the entry or leaves the subagent
running unattended. ([#5069])
- **subagents:** Stop the zombie PENDING registry entry on the submit-failure
path, and derive the capacity snapshot's queued count from the waiters'
length instead of iterating a deque other threads mutate. ([#5086])
- **channels:** Synchronize `ChannelStore` reads with mutations, so
`get_thread_id()`/`list_entries()` can no longer raise `dictionary changed
size during iteration`. ([#5083])
- **discord:** Retain strong references to ack-reaction tasks and drain them
on shutdown, so a GC pass can no longer silently drop a reaction or pin the
channel across restart cycles. ([#5049])
- **buzz:** Move seen-event persistence off the event loop with coalesced
atomic writes, preserving dirty generations when events arrive mid-write
and awaiting the final flush on shutdown. ([#5103])
- **streaming:** Stop an `IndexError` in `MemoryStreamBridge._make_gap` when a
subscriber reconnects to an empty or drained stream with an expired cursor.
([#5047])
- **uploads:** Keep deduplicated filenames within the 255-byte limit by
truncating the stem on a UTF-8 code-point boundary, so two max-length files
that differ only by a dedupe suffix upload successfully instead of failing
the whole batch. ([#5059])
- **frontend:** Format structured upload error details (FastAPI validation
issues, objects, arrays) instead of showing `[object Object]`. ([#5071])
- **frontend:** Keep a renamed thread's title in sync across the active chat
header, document title, search results, and metadata caches without a
reload. ([#5045])
- **frontend:** Truncate selected model names to the selector button width, so
long model names ellipsize in the composer and sidecar instead of
overflowing. ([#5050])
- **frontend:** Truncate long subtask card titles to one line with a tooltip,
so a delegation whose model omitted `description` (falling back to the full
prompt) no longer overflows the chat layout. ([#5136])
- **dev:** Default the frontend dev server to Webpack on all platforms
(`DEER_FLOW_DEV_BUNDLER=turbo` opts back into Turbopack), avoiding
Turbopack's macOS PostCSS worker leak and its Windows runtime panics.
([#5036], [#5133])
- **scripts:** Run repo shell scripts through an explicit interpreter
(`bash scripts/...`), so a lost executable bit - zip/tarball downloads,
`core.fileMode=false`, non-POSIX filesystems - no longer breaks
`make docker-start` and friends with `Permission denied`. ([#5031])
- **deps:** Depend on the renamed `tenki` package instead of the PyPI-removed
`tenki-sandbox` (same `tenki_sandbox` import), so clean checkouts can
resolve dependencies again on `make dev`/`uv sync`. ([#5087])
- **memory:** Memory reads configured to stop the turn now raise a
backend-neutral `MemoryReadError` that prompt assembly preserves instead
of swallowing: strict OpenViking (`read: raise`), Mem0, and Honcho reads
propagate, OpenViking scope-resolution failures follow the configured read
policy, and the 5-second injection deadline honors the same policy
(fail-open continues without the context; strict raises with the timeout
as its cause). ([#4726])
- **memory:** Buffered memory extraction is cancelled when a custom agent is
deleted or cleared, so pending debounce timers can no longer resurrect the
deleted per-agent memory scope or overwrite a fresh clear with a stale
pending update. ([#5123])
- **agents:** Conversation titles are generated from the user's original
message content when upload (or other) context wrappers have been injected
into the text, so titles no longer quote server-injected
`<current_uploads>` context; attachment-only messages keep the
`New Conversation` fallback. ([#4729])
- **agents:** Fraction summarization triggers resolve against the model's
declared `context_window` (now translated into the LangChain profile), and
an unresolvable fraction clause degrades to a never-firing trigger with a
warning instead of crashing the whole agent build; percent-style and
non-finite trigger values are rejected at config load. ([#4901])
- **agents:** Custom-agent storage falls back to file-backed storage only
when search mode cannot resolve the main application config — invalid
configuration and missing config paths surface instead of silently
switching storage backends — and store IO moves off the event loop in
async agent routes. ([#4952])
- **middleware:** Loop-detection hard stops win across a whole tool-call
batch: selecting a soft warning no longer ends inspection, so a later call
in the same response that crosses an operator-configured hard limit is
rejected instead of riding along with the earlier warning. ([#5245])
- **sandbox:** `list_dir` and `glob` in the five remote sandbox providers
(E2B, OpenSandbox, AIO, Tenki, BoxLite) return filenames verbatim instead
of stripping whitespace, so files whose names begin or end with spaces are
no longer listed under paths that then do not exist. ([#4980])
- **sandbox:** Concurrent subagents sharing one thread sandbox run under
process-local execution leases with task-scoped AIO shell sessions, so one
sibling finishing can no longer release the shared sandbox underneath the
others or corrupt the implicit persistent session; a healthy replacement
session is promoted after corruption instead of returning to it. ([#5134])
- **sandbox:** The Bash tool guides the agent to detect its execution
environment with evidence (`uname -s`, `sw_vers`, `uname -a`) instead of
model assumptions, and rejected host paths direct it to command-only
probes or allowed virtual paths rather than repeating the blocked command.
([#5111])
- **sandbox:** The Docker AIO compatibility capability allowlist gains
`FOWNER`, so AIO images whose startup `chmod`s `/run/user/1000` (e.g.
1.11.0) start again under the hardened default capabilities while
`no-new-privileges` stays on. ([#5163])
- **sandbox:** File appends no longer destroy existing content when the
pre-read fails: E2B append treats only missing-file errors as an empty
file and re-raises anything else instead of overwriting the file with just
the appended tail, and AIO appends use the server's native append mode
without a pre-read at all. ([#5261], [#5278])
- **skills:** Skill markdown is read explicitly as UTF-8, so localized skills
validate on Windows hosts whose default code page is not UTF-8 instead of
failing with `UnicodeDecodeError`. ([#4995])
- **mcp:** The MCP tools cache re-initializes after a runtime config change:
a module-level `asyncio.Lock` bound to a closed event loop and an
unsynchronized initialized flag had left every post-update call failing
with `Lock is bound to a different event loop` or racing across worker
threads. ([#5062])
- **mcp:** Sync-wrapped MCP tools keep LangGraph `ToolRuntime` injection (the
annotation-less sync wrapper is now `functools.wraps`-transparent), so
per-user scope resolution and durable task submission no longer run with
`runtime=None` — which had routed completion-notification runs under the
default lead agent instead of the thread's custom agent. ([#5164])
- **auth:** A duplicate OAuth identity no longer reports "Email already
registered" — the two integrity violations are distinguished — and the
partial OAuth-identity index now declares `postgresql_where` so Postgres
builds the intended partial index instead of a full one. ([#5026])
- **frontend:** The mobile sidebar trigger stays clickable on regular and
custom-agent welcome pages, where multi-line (longer localized) welcome
text in a same-`z-index` overlay could cover the header's tappable area.
([#5149])
- **subagents:** `SubagentResult` lifecycle timestamps are UTC-aware on
every writer, matching the repo-wide convention instead of stamping local
wall-clock time on non-UTC hosts. ([#5153])
- **browser:** Background live-frame scheduler tasks retain strong
references, so garbage collection can no longer silently stop the Browser
Live view from refreshing by stranding a pending guard that was cleared
only in a collected task's `finally`. ([#5155])
- **runtime:** Duplicate `on_llm_end` callbacks for the same LangChain run id
persist one durable `llm.ai.response` event (replayed usage merged by
generation position, first callback canonical), so append-only message
APIs no longer return duplicate responses from providers that re-fire the
callback with usage populated. ([#5187])
- **runtime:** Terminal finalization completes after a cancellation raised
inside the completion hook or task-stop fan-out, so extension observers
run and the stream END marker is published before the interruption is
re-raised; the finalization tail stays interruptible. ([#5191])
- **models:** A cancelled LLM call releases its owned circuit-breaker
recovery probe across provider execution, concurrency admission, and
backoff, so subsequent calls no longer see `CircuitBreakerOpen` after a
cancellation; probe ownership is fenced by a per-call token so cancelling
an older call cannot release another call's probe. ([#5197])
- **runtime:** The embedded `DeerFlowClient` keys its graph cache by
effective user in every authorization mode and materializes the same user
in runtime context, so sequential reuse for different users can no longer
serve a graph assembled with another user's prompt and workspace state.
([#5206])
- **runtime:** Cancelled workspace-change snapshot captures drain their
already-running scan and clean up the per-run text cache instead of
leaking `deerflow-workspace-changes-*` directories, while metadata-only
captures propagate cancellation promptly without waiting on the scan.
([#5232], [#5234])
- **persistence:** Gateway startup tolerates a database already migrated to
the explicitly-reviewed newer revision (`0019_thread_incarnations`), so
rolling back to this image after a newer deployment stays possible; other
unknown revisions, an empty version table, and multiple version rows
still fail closed. ([#5219])
- **community:** Tavily Extract results without a `title` fall back to the
result or requested URL as the display heading instead of raising
`KeyError` and discarding usable page content. ([#5280])
- **uploads:** Fenced code blocks are excluded from uploaded-document
outlines, so code comments and bold examples inside fences no longer
crowd real sections out of the 50-entry heading budget. ([#5281])
- **subagents:** After compaction, the delegation ledger distinguishes
execution completion from task acceptance and preserves bounded examples
of a completed subagent's unmet and unverified acceptance criteria, so the
lead agent repairs the remaining gaps instead of treating the completed
result as fully done. ([#5287])
- **dev:** `_pick_python()` validates interpreter candidates through
`/usr/bin/env`, mirroring how the frontend is launched, so `make dev`
starts the frontend on Windows where Microsoft Store Python stubs satisfy
Bash-side probes but not `env`. ([#5181])
### Performance
- **runtime:** Index `MemoryRunStore` by `thread_id` and `MemoryRunEventStore`
events by `run_id` to avoid O(n) scans. ([#3562], [#3686])
- **subagents:** Deduplicate streamed AI messages via a seen-id set (O(n²) ->
O(n)). ([#3687])
- **sandbox:** Cache `LocalSandbox` path-rewrite regexes and local-path masking
patterns per instance instead of recompiling per search match. ([#3648],
[#3713])
- **messages:** Index tool-call results per group. ([#4411])
- **frontend:** Coalesce streaming renders to a frame budget instead of per
chunk. ([#4425])
- **frontend:** Stop re-deriving message content on every stream chunk.
([#4441])
- **sandbox:** `read_file` reads only the requested line range from the
sandbox instead of fetching the whole file first. ([#3824])
- **browser:** Encode Browser Live progress frames as JPEG to cut progress
payload size. ([#4836])
- **middleware:** Inject `view_image` content via `wrap_model_call` instead of
a checkpointed hidden message, so up to 20 MB of base64 no longer sits in
two checkpoints per viewed image and an interrupted run can no longer leave
the payload behind. ([#5014])
- **frontend:** Cache settled copy-data derivation across streaming chunks, so
each chunk no longer re-derives toolbar/copy text for every settled
message. ([#5095])
- **runtime:** Bound gateway memory after terminal runs, stopping the post-GC
low-water mark from creeping upward across completed sessions. ([#5112])
- **frontend:** Chat streams request `messages-tuple` + `updates` + `custom`
instead of full `values` state snapshots — the retransmitted historical
`values` messages were ~75% of SSE payload — folding reducer events into
rendered state locally while keeping full snapshots only for replay-gap
recovery. ([#5159])
### Security
- **prompt-injection:** New input-sanitization middleware defends against
prompt-injection, forged framework tags in the input guardrail are blocked,
and system context is injected as a `SystemMessage` for role isolation. ([#3662],
[#4155], [#3661])
- **prompt-injection:** HTML-escape untrusted content rendered into model prompts
- memory facts and summaries, `SOUL.md`, subagent descriptions, skill metadata,
and the conversation block in the memory-update prompt - and neutralize
prompt-injection tags in `web_capture` tool results. ([#4028], [#4119], [#4137],
[#4157], [#4162], [#4099], [#4060], [#4097], [#4128])
- **prompt-injection:** Close two input-sanitization bypasses. `hide_from_ui` and
a human `name="summary"` tell `is_genuine_user_message` that the framework
authored a message, which skips sanitization entirely. Untrusted run input and
thread-state writes carrying either marker are now marked server-side and
sanitized regardless, so a caller can no longer land a raw `<system-reminder>`
outside the user-input boundary markers that the lead-agent prompt declares
trusted framework data. The markers themselves are preserved, so messages that
use `hide_from_ui` only to stay out of the transcript — quoted conversation
context, sidecar context, the agent save command, HumanInputCard replies — keep
doing that, and trusted internal launchers are unaffected. Sanitization also
covers every genuine user message instead of only the newest: the
transformation is request-scoped, so a last-turn-only scan neutralized a
payload for exactly one model call and then replayed it verbatim from the next
turn on. ([#5375])
- **secrets:** Scrub inherited secret environment variables (`MYSQL_PWD`,
`REDISCLI_AUTH`, abbreviated `*_PASS`, and Postgres `PGPASSFILE`) from the
skill environment; request-scoped secrets are bound for both slash-activated
and autonomously-invoked skills. ([#4018], [#4026], [#3871], [#3938])
- **web_fetch:** SSRF guard for self-hosted providers. ([#3942])
- **guardrails:** An empty allowlist now denies all tools instead of failing
open. ([#4067])
- **authz:** Global skills-management endpoints now require admin; the legacy
skills mount is gated by user visibility; artifacts honor a trusted
`owner-user-id` header; and the trusted authorization principal is propagated
through the runtime. ([#3855], [#3985], [#3982], [#4203])
- **auth:** Persist the `csrf_token` cookie for the access-token lifetime.
([#3872])
- **storage:** Stop persisting base64 image data in checkpoint state. ([#4140])
- **mcp:** Reject legacy MCP credentials in run metadata. ([#4448])
- **mcp:** Constrain stdio launcher arguments and environment variables at
the config API, rejecting launcher flags and env names that could turn an
allowlisted `npx`/`uvx` server registration into arbitrary code execution.
([#4617])
- **auth:** Harden validation of the post-login `next` path. ([#4587])
- **runtime:** Honor the LangGraph Server's authenticated user identity
across agents, uploads, thread data, memory, and skills, and reject
client-supplied auth identity fields. ([#4538])
- **frontend:** Send the session cookie on model, workspace-change, and
ranged artifact reads in split-origin deployments. ([#4827])
- **frontend:** Restore sanitization in custom streamdown rehype chains, so
artifact markdown previews and the memory settings summary can no longer
render hostile HTML such as `javascript:` links or `on*` event handlers.
([#4987])
- **skills:** Copy projected skill files instead of hardlinking them, so a
sandboxed write can no longer mutate the canonical skill source, and fail
closed on a drifted projection namespace on every platform, including
Windows. ([#4825], [#4830])
- **scripts:** Redact secret-shaped keys (`db_pass`, `signing_key`, ...)
wherever they appear in bundled config, not only under well-known key
names. ([#4242])
- **sandbox:** Sanitize MCP-sourced tool results through the same trust
boundary as the built-in web tools, so a hostile or compromised MCP server
can no longer hand the model forged `<system-reminder>` or user-input
boundary tags. ([#4839])
- **sandbox:** Harden local Docker sandbox containers: published ports bind
the Docker bridge gateway instead of `0.0.0.0` when the sandbox host is
non-loopback (`DEER_FLOW_SANDBOX_BIND_HOST=0.0.0.0` restores the broad
bind), Docker's default seccomp profile replaces unconditional
`seccomp=unconfined` (opt back in with `DEER_FLOW_SANDBOX_SECCOMP_UNCONFINED=1`),
and containers drop all capabilities, get `no-new-privileges`, and run with
bounded resources. ([#4986])
- **authz:** Enforce run-create authorization on stateless stream/wait
endpoints (`runs:create`), and require both `threads:write` and
`runs:create` for scheduled-task create, update, resume, and manual-trigger
mutations. ([#5030])
- **authz:** Re-check the authorization policy before reusing a persisted
sandbox, so a revoked `sandbox:execute` grant takes effect on the next
sandbox-backed turn instead of outliving the policy in the cached sandbox.
([#5006])
- **skills:** Enforce custom-Agent skill allowlists at the sandbox filesystem
level: an explicit `skills` policy materializes a signed per-user/thread
skills view, so a custom agent with shell or file tools can no longer read
skills its policy excludes. ([#5077])
- **runs:** Reject cancel/rollback actions on GET stream joins with
`405 Method Not Allowed` - cancel-then-stream is a POST operation - closing
a state change that CSRF middleware deliberately exempted on safe methods;
action-less GET joins are unchanged. ([#5092])
- **lark:** Lark CLI credential trees on Windows enforce private ACLs
(gateway-SID-only protected DACL, reparse-point rejection, handle-relative
traversal), extending the POSIX `0700`/`0600` confidentiality contract
against inherited grants, junction redirection, hard-link aliasing, and
TOCTOU replacement. ([#5141])
- **sandbox:** `SSH_AUTH_SOCK` is scrubbed from the sandbox subprocess
environment — inheriting the host ssh-agent socket lets sandboxed code
sign and authenticate with every key the agent holds — unless a skill
explicitly declares it via required-secrets. ([#5145])
- **artifacts:** Serve XML artifacts as download attachments like HTML and
SVG. `GET /api/threads/{id}/artifacts/{path}` rendered `.xml`, `.xsl`, and
`.rdf` files — and `+xml` types such as `.rss` wherever the host MIME
database maps them — inline in the application origin, so an XML document
with an XHTML-namespaced `<script>`, written by a prompt-injected agent and
opened from a chat link, could call the API with the viewer's session.
Every XML MIME type (`text/xml`, `application/xml`, `text/xsl`, any `+xml`
subtype) is now treated as active content, including `.skill` archive
members; the artifacts panel keeps previewing XML through its ranged fetch.
([#5353])
### Documentation
- **docs:** Clarify how `LocalSandboxProvider` resolves `sandbox.mounts[].host_path`
under production Docker, with gateway bind-mount and config examples. ([#3833])
- **docs:** Document that Crawl4AI >= 0.9 requires a bearer token. ([#4518])
- **docs:** Document the GitHub inbound-dedupe TTL semantics, including what
redeliveries are not deduped, and tighten the redelivery tests. ([#4274])
- **docs:** Update the agent AGENTS.md and ARCHITECTURE.md guides. ([#4817])
- **docs:** Document the Honcho memory backend with a dedicated guide and a
long-term memory section entry in the README. ([#4822])
- **docs:** Align custom-agent documentation with the API across the English
and Chinese agents/threads/lead-agent pages: the required ASCII `name`
request field, lowercase storage, `/api/agents/check` name-availability
behavior, and no auto-derived slug from `display_name`. ([#4944])
### Internal
- **tests:** Migrate frontend unit tests to rstest and run hook-level tests in
a DOM environment. ([#3703], [#4453])
- **tests:** Require explicit opt-in for live client tests. ([#4482])
- **tests:** Rename the LLM-error test stand-in instead of the shared
FakeError. ([#4744])
- **tests:** Replace the magic unwritable absolute path in tool-output tests
with a self-constructed failure condition. ([#4722])
- **tests:** Add multi-turn message-stream invariants as graph integration
tests. ([#3708])
- **tests:** Add trace-based behavioral tests with Monocle Test Tools,
asserting agent routing, tool calls, and token/duration cost. ([#4025])
- **tests:** Cover passive skill tool visibility in the MCP layer. ([#4247])
- **tests:** Add SQL and concurrent-reconciler coverage for lease-aware orphan
recovery. ([#4427])
- **tests:** Restore memory updater regression coverage. ([#4490])
- **tests:** Lock in POST logout from the gateway-offline banner. ([#4506])
- **tests:** Document known instance-client false negatives in the SkillScan
tests. ([#4644])
- **refactor:** Extract frontend placeholder detection into a tested utility.
([#3783])
- **refactor:** Consolidate E2B client lifecycle helpers and reuse the kill
helper during warm-pool eviction. ([#4262], [#4298])
- **refactor:** Name the E2B capacity-ledger meta-field count so the admission
offset is explicit. ([#4764])
- **dev:** Trace self/cls attribute chains and local aliases in the
blocking-IO detector's call graph, closing false negatives. ([#4200])
- **ci:** Publish the lark-cli-init and lark-broker images. ([#4558])
- **dev:** Route host-side pnpm consumers through a shared runner with a
Corepack fallback so local workflows work without a pnpm shim. ([#4405])
- **bench:** Add an isolated checkpoint channel-mode benchmark comparing `full`
and `delta` across latency, storage, and replay metrics. ([#4395])
- **deps:** Bump `cryptography` 49.0.0 -> 50.0.0, `postcss` 8.4.31 -> 8.5.25,
`h2` 4.3.0 -> 4.4.1, `langgraph-checkpoint-sqlite` and
`langgraph-checkpoint-postgres` 3.1.0 -> 3.1.1, and `nanoid` 5.1.6 -> 5.1.16.
([#4681], [#4683], [#4737], [#4738], [#4747], [#4748])
- **bench:** Add a reproducible hybrid memory-eviction evaluation under
`backend/scripts/benchmark/deermem_eviction/` with a deterministic,
blind-by-construction grader for the #4789 policy. ([#4810])
- **bench:** Measure Postgres checkpoint/blob/write storage growth in the
checkpoint benchmark alongside memory and SQLite. ([#5051])
- **tests:** Exclude `tests/blocking_io/` from `make test`; the dedicated
`make test-blocking-io` suite (and its CI workflow) remains the owner.
([#5105])
- **refactor:** Share sandbox identity derivation and acquire serialization
across the five remote sandbox providers (RFC #4741), replacing five
per-provider lock tables that grew unboundedly with process lifetime;
derived ids are pinned byte-identical by per-provider golden vectors.
([#5089])
- **ci:** Split the backend unit-test workflow into four parallel shards —
each on its own runner with isolated Postgres/Redis — using `pytest-split`
with a committed duration baseline and failing closed when the baseline is
missing; `make test` remains the canonical full offline suite.
([#5137])
- **dev:** Launch the Playwright `webServer`'s Next.js through `pnpm exec`,
so Windows E2E runs resolve the platform package binary instead of failing
on the extensionless POSIX shim. ([#5185])
- **tests:** Skip the POSIX mode-bit skill-permission assertions on Windows,
where the `chmod` contract is unobservable, so Windows contributors can
reach a green backend-suite baseline. ([#5244])
## [2.0.0] — 2026-06-15
DeerFlow 2.0 is a ground-up rewrite around a "super agent" harness with
sub-agents, persistent memory, sandbox execution, and an extensible
skills/tools system. It shares no code with the 1.x line, which now lives on
the [`main-1.x` branch](https://github.com/bytedance/deer-flow/tree/main-1.x).
This release closes [milestone 2.0.0](https://github.com/bytedance/deer-flow/milestone/1)
with **180 merged pull requests** since the first 2.0 milestone tag.
### ⚠ Breaking changes
- **harness:** Hydrate runs from `RunStore` and persist interrupted status. Run
cancellation/multitask semantics now require a working RunStore on the
worker that owns the run; cross-worker cancels return 409 instead of
silently appearing successful. ([#2932])
### Added
#### Agents & runtime
- **agent:** Custom-agent self-updates with user isolation — agents can persist
edits to their own `SOUL.md` / `config.yaml` from inside a normal chat.
([#2713])
- **loop-detection:** Make loop detection configurable with per-tool frequency
overrides; keep configurable on/off switch. ([#2586], [#2711])
- **loop-detection:** Defer warning injection so detector pairs cleanly with
tool-call lifecycle. ([#2752])
- **run:** Propagate `model_name` from the gateway request through the runtime
and persistence stack into the SQLite-backed store. ([#2775])
- **subagents:** Stream subagent token usage to the header via terminal task
events. ([#2882])
- **memory:** Add `memory.token_counting` config to opt out of tiktoken for
network-restricted deployments. ([#3465])
- **suggest:** Make AI follow-up question suggestions optional. ([#3591])
#### Models & integrations
- **models:** Add StepFun reasoning model adapter. ([#3461])
- **community:** Add Brave Search web search tool. ([#3528])
- **channels:** Enhance Discord with mention-only mode, thread routing, and
typing indicators. ([#2842])
- **im:** Add user-owned IM channel connections — users can bind their own
Slack/Telegram/Discord/Feishu/DingTalk/WeChat/WeCom accounts on top of the
operator-configured bots. ([#3487])
- **models:** Add patched MiMo reasoning content support. ([#3298])
- **models:** Add MiniMax provider for image/video/podcast skills plus a new
music-generation skill. ([#3437])
- **community:** Add SearXNG and Browserless web search/fetch tools. ([#3451])
- **community:** Add Serper Google Images provider for `image_search`. ([#3575])
- **channels:** Stream Telegram agent replies by editing the placeholder
message in place. ([#3534])
#### Observability
- **trace:** Set the LangGraph trace name to `lead_agent` (or the custom
agent's `agent_name`) for cleaner Langfuse/LangSmith traces. ([#3101])
- **frontend:** Refine token usage display modes. ([#2329])
- **defaults:** Enable token usage tracking by default. ([#2841])
- **defaults:** Raise default summarization trigger threshold. ([#3174])
- **trace:** Attribute subagent spans to the parent thread's Langfuse trace.
([#3611])
#### Skills
- **skill:** Add `blocking-io-guard` skill for blocking-IO triage and runtime
anchors. ([#3503])
- **skill:** Add maintainer issue and PR workflow skill. ([#3554])
- **skill:** Strengthen the maintainer orchestrator review workflow. ([#3606])
### Performance
- **harness:** Push thread metadata filters into SQL instead of post-filtering
in Python. ([#2865])
- **runtime:** Index runs by `thread_id` to avoid O(n) scans in `RunManager`.
([#3499])
- **runtime:** Index messages in `MemoryRunEventStore` to avoid O(n) scans.
([#3531])
- **persistence:** Cache `Base.to_dict` column reflection per class. ([#3654])
- **sandbox:** Speed up `should_ignore_name` in glob/grep walks. ([#3657])
### Security
- **upload:** Reject symlinked upload destinations. ([#2623])
- **uploads:** Add Windows support for safe symlink-protected uploads.
([#2794])
- **mcp:** Mask sensitive values in MCP config API responses. ([#2667])
- **mcp:** Harden the MCP config endpoint against malformed input. ([#3425])
- **auth:** Reject cross-site auth POSTs. ([#2740])
- **gateway:** Cap skill artifact preview decompression to prevent
zip-bomb-style abuse. ([#2963])
- **sandbox:** Mount the host Docker socket only in aio (DooD) sandbox mode.
([#3517])
- **sandbox:** Do not bind-mount host CLI auth dirs by default. ([#3521])
### Fixed
#### Runtime, gateway & persistence
- **runtime:** Rollback restore checkpoint now supersedes newer checkpoints.
([#2582])
- **runtime:** Persist run message summaries. ([#2850])
- **runtime:** Bound `write_file` execution-failure observations to keep
failure traces from blowing out the context. ([#3133])
- **runtime:** Protect the sync singleton's init and reset paths. ([#3413])
- **runtime:** Avoid PostgreSQL aggregate `FOR UPDATE` on run events.
([#2962])
- **runs:** Restore historical runs from persistent store after a gateway
restart. ([#2989])
- **gateway:** Return ISO 8601 timestamps from threads endpoints. ([#2599])
- **gateway:** Make cancel idempotent for already-interrupted runs. ([#3058])
- **gateway:** Split `stream_existing_run` into per-method routes for unique
OpenAPI `operationId`s. ([#3228])
- **events:** Serialize structured DB event content. ([#2762])
- **persistence:** Emit timezone-aware timestamps from SQLite-backed stores.
([#3130])
- **persistence:** Reuse token usage model grouping expression. ([#2910])
- **runs:** Ignore stale run reconnect conflicts. ([#3284])
- **nginx:** Defer CORS to the gateway allowlist instead of double-applying it.
([#2861])
- **persistence:** Fix runtime journal run lifecycle events. ([#3470])
- **gateway:** Enforce thread ownership on stateless run endpoints. ([#3473])
- **runtime:** Propagate interrupt through SSE values events for the LangGraph
SDK. ([#3605])
- **serialization:** Strip base64 image data from streamed values events.
([#3631])
- **history:** Strip base64 image data from REST endpoint responses. ([#3535])
- **gateway:** Attribute token usage to the actual models. ([#3658])
#### Agents, subagents & middleware
- **subagents:** Make subagent timeout terminal state atomic. ([#2583])
- **subagents:** Use model override for tools and middleware. ([#2641])
- **subagents:** Consolidate `system_prompt` and skills into a single
`SystemMessage`. ([#2701])
- **subagent:** Isolate subagents from the parent run's checkpointer.
([#3559])
- **agents:** Make `update_agent` honor `runtime.context` `user_id` like
`setup_agent` does. ([#2867])
- **agents:** Resolve duplicate `todos` channel type conflict in
`TodoMiddleware`. ([#3200])
- **agents:** Offload blocking filesystem IO in the custom-agent router off
the event loop. ([#3457])
- **agents:** Keep new agent bootstrap in user scope. ([#2784])
- **loop-detection:** Keep tool-call pairing on warn injection. ([#2725])
- **middleware:** Sync raw tool-call metadata. ([#2757])
- **middleware:** Handle invalid tool calls in dangling pairing middleware.
([#2891])
- **middleware:** Prevent todo completion reminder IM-message leak. ([#2907])
- **middleware:** Normalize tool result adjacency before model calls.
([#2939])
- **agents:** Require `config.yaml` in `resolve_agent_dir` to skip memory-only
directories. ([#3481])
- **agents:** Sync `agent_name` across context/configurable and reject empty
soul. ([#3553])
- **middleware:** Offload the uploads scan in `UploadsMiddleware` off the event
loop. ([#3311])
- **middleware:** Offload memory injection off the event loop to prevent
tiktoken blocking. ([#3411])
- **middleware:** Externalize oversized tool output into the sandbox for
non-mounted sandboxes. ([#3417])
- **middleware:** Preserve the sandbox reducer in middleware state. ([#3629])
- **subagents:** Raise general-purpose `max_turns` to 150 and default timeout to
30 min. ([#3610])
#### Memory & tracing
- **memory:** Replace short-lived `asyncio.run()` with a persistent event
loop. ([#2627])
- **memory:** Isolate queued memory updates by agent. ([#2941])
- **memory:** Parse wrapped memory-update JSON responses. ([#3252])
- **tracing:** Propagate `session_id` and `user_id` into Langfuse traces.
([#2944])
- **trace:** Decode unicode escape sequences in non-ASCII memory trace info.
([#3104])
#### Tools, sandbox & MCP
- **mcp:** Fix env resolution in MCP config lists. ([#2556])
- **models:** Record Codex token usage in `usage_metadata`. ([#2585])
- **sandbox:** Supplement `list_running` in `RemoteSandboxBackend`. ([#2716])
- **sandbox:** Disable MSYS path conversion for Git Bash on Windows.
([#2766])
- **sandbox:** Avoid blocking sandbox readiness polling. ([#2822])
- **sandbox:** Uphold the `/mnt/user-data` contract at the `Sandbox` API
boundary. ([#2881])
- **sandbox:** Scope provisioner PVC data by user. ([#2973])
- **sandbox:** Merge idempotent sandbox state updates. ([#3518])
- **tools:** Introduce `Runtime` type alias to eliminate Pydantic serialization
warnings. ([#2774])
- **tools:** Preserve `tool_search` promotions across re-entrant
`get_available_tools`. ([#2885])
- **harness:** Wrap async-only config tools for sync client execution.
([#2878])
- **harness:** Wrap all async-only tools for sync clients. ([#2935])
- **tool-search:** Reliably hide deferred MCP schemas by removing the
ContextVar. ([#3342])
- **search:** Fix DDGS Wikipedia region handling. ([#3423])
- **web_fetch:** Support a proxy for the Jina reader in restricted networks.
([#3430])
- **sandbox:** Persist lazily-acquired sandbox state via `Command`. ([#3464])
- **sandbox:** Fix stale AIO sandbox cache reuse. ([#3494])
- **sandbox:** Create a shell session before retrying on a fresh id. ([#3577])
- **sandbox:** Stop flagging string-literal path fragments as unsafe absolute
paths. ([#3623])
- **sandbox:** Return an actionable hint when `read_file` hits a binary file.
([#3624])
- **mcp:** Make stdio MCP-produced files resolvable via virtual sandbox paths.
([#3600])
- **mcp:** Surface admin-required state on the settings tools page. ([#3533])
- **mcp:** Add a tools cache reset endpoint. ([#3602])
- **uploads:** Fix the upload file size contract. ([#3408])
#### Skills & channels
- **skills:** Enforce `allowed-tools` metadata. ([#2626])
- **skills:** Harden slash skill activation across chat channels. ([#3466])
- **skills:** Fix custom skill install permissions. ([#3241])
- **channels:** Authenticate gateway command requests. ([#2742])
- **skills:** Surface the offending line and a quoting hint on SKILL.md YAML
errors. ([#3335])
- **skills:** Keep skill archive installation off the event loop. ([#3505])
- **channels:** Ignore hidden control messages when extracting replies.
([#3270])
- **channels:** Reload config on channel restart. ([#3514])
- **channels:** Surface WeCom WebSocket connection failures. ([#3526])
- **channels:** Close the Discord file handle after upload. ([#3561])
- **channels:** Require a bound identity for user-owned IM messages. ([#3578])
- **channels:** Scope IM files and helper commands to the owner. ([#3579])
- **channels:** Make runtime provider state authoritative. ([#3580])
- **channels:** Harden runtime credential management APIs. ([#3581])
- **channels:** Make the channel connect flow deterministic. ([#3582])
- **channels:** Centralize shared channel retry helpers. ([#3583])
- **channels:** Add operational guardrails. ([#3584])
- **channels:** Unsubscribe channel listeners by equality. ([#3608])
#### Auth
- **auth:** Replace setup-status 429 rate limit with a cached response.
([#2915])
- **auth:** Persist auto-generated JWT secret so it survives restarts.
([#2933])
- **auth:** Align auth-disabled mode with mock history loading. ([#3471])
#### Frontend
- **frontend:** Restore `localhost` fallback for `getGatewayConfig` in prod
mode. ([#2718])
- **chat:** Prevent the first user message from being swallowed in new
conversations. ([#2731])
- **frontend:** Use backend thread token usage for the header total. ([#2800])
- **frontend:** Wait for async chat submit before clearing the input.
([#2940])
- **frontend:** Resolve login page flickering and the resize-observer loop.
([#2954])
- **frontend:** Deduplicate restored thread messages. ([#2958])
- **frontend:** Avoid duplicate optimistic user message. ([#3002])
- **frontend:** Hide the copy button for streaming assistant messages.
([#3176])
- **frontend:** Show a new thread in the sidebar immediately on creation.
([#3283])
- **frontend:** Isolate new chat thread messages. ([#3508])
- **frontend:** Cap deeply nested list indentation to prevent render crashes.
([#3393], [#3570])
- **token-usage:** Dedupe token usage aggregation by message id. ([#2770])
- **frontend:** Fall back to Streamdown clipboard copy. ([#3397])
- **frontend:** Remove the Backspace shortcut for deleting prompt attachments.
([#3410])
- **frontend:** Restructure the Memory settings toolbar into two rows. ([#3433])
- **suggestions:** Strip inline `<think>` reasoning before parsing follow-up
questions. ([#3435])
- **frontend:** Stop fetching follow-up suggestions when they are disabled.
([#3599])
- **frontend:** Paginate the workspace chat list beyond 50 threads. ([#3485])
- **frontend:** Prevent user message bubble overflow with long unbreakable
strings. ([#3488])
- **frontend:** Keep the workspace interactive when the SSR auth probe cannot
reach the gateway. ([#3495])
- **frontend:** Render user messages as plain text and cap blockquote nesting.
([#3502])
- **frontend:** Reset the active chat after deletion. ([#3519])
- **frontend:** Improve the mobile workspace layout. ([#3646])
- **frontend:** Render full content for multi-part AI messages. ([#3649])
#### Build, deploy, scripts & config
- **packaging:** Add `postgres` extra for store/checkpointer support; clarify
install guidance. ([#2584])
- **harness:** Resolve runtime paths from the project root. ([#2642])
- **docker:** Force nginx to resolve upstream names at request time.
([#2717])
- **docker:** Default Gateway to a single worker to prevent multi-worker
breakage. ([#3475])
- **scripts:** Preserve `uv` extras across `make dev` restarts. ([#2767],
[#2754])
- **scripts:** Clean up local nginx on stop. ([#3005])
- **deploy:** Fall back to `python` / `openssl` when `python3` is absent for
secret generation. ([#3074])
- **config:** Make the reload boundary discoverable from code. ([#3144],
[#3153])
- **replay-e2e:** Key replay fixtures by caller and conversation. ([#3453])
- **setup:** Refresh LLM provider wizard defaults. ([#3421])
- **config:** Coerce null `config.yaml` list sections to an empty list. ([#3434])
- **scripts:** Exclude runtime state from gateway reload. ([#3426])
- **scripts:** Create the backend/sandbox dir before the uvicorn reload-exclude.
([#3460])
- **scripts:** Stop next-server correctly after `make start-daemon`. ([#3498])
- **makefile:** Fix per-commit hooks installation. ([#3569])
- **replay-e2e:** Match replay by conversation, not the living system prompt.
([#3436])
### Changed
- **provider (refactor):** Share assistant payload replay matching across
providers. ([#3307])
- **lead-agent (refactor):** Make `build_middlewares` public to drop the last
cross-module private import. ([#3458])
- **todo (refactor):** Remove the unused completion reminder counter. ([#3530])
### Documentation
- Document blocking-IO detection usage and maintenance. ([#3233])
- Clean standalone LangGraph server remnants from docs. ([#3301])
- Add AI assistance disclosure to the PR template and CONTRIBUTING. ([#3398])
- Document custom AIO sandbox images. ([#3548])
### Internal
- **dev:** Add async/thread boundary detector. ([#2936])
- **runtime:** Add lifecycle end-to-end coverage. ([#2946])
- **windows:** Add `PYTHONIOENCODING` and `PYTHONUTF8` to backend Makefile
targets. ([#3069])
- **blocking-io:** Fail-loud repo-root resolution and shared detector CLI
shim. ([#3512])
- **runtime:** Add a Blockbuster runtime anchor for `JsonlRunEventStore` async
IO. ([#3313])
- **ci:** Consolidate PR/issue labeling and fix the reviewing-job crash and
label thrash. ([#3455])
[2.0.0]: https://github.com/bytedance/deer-flow/releases/tag/v2.0.0
[#2329]: https://github.com/bytedance/deer-flow/pull/2329
[#2556]: https://github.com/bytedance/deer-flow/pull/2556
[#2582]: https://github.com/bytedance/deer-flow/pull/2582
[#2583]: https://github.com/bytedance/deer-flow/pull/2583
[#2584]: https://github.com/bytedance/deer-flow/pull/2584
[#2585]: https://github.com/bytedance/deer-flow/pull/2585
[#2586]: https://github.com/bytedance/deer-flow/pull/2586
[#2599]: https://github.com/bytedance/deer-flow/pull/2599
[#2623]: https://github.com/bytedance/deer-flow/pull/2623
[#2626]: https://github.com/bytedance/deer-flow/pull/2626
[#2627]: https://github.com/bytedance/deer-flow/pull/2627
[#2641]: https://github.com/bytedance/deer-flow/pull/2641
[#2642]: https://github.com/bytedance/deer-flow/pull/2642
[#2667]: https://github.com/bytedance/deer-flow/pull/2667
[#2701]: https://github.com/bytedance/deer-flow/pull/2701
[#2711]: https://github.com/bytedance/deer-flow/pull/2711
[#2713]: https://github.com/bytedance/deer-flow/pull/2713
[#2716]: https://github.com/bytedance/deer-flow/pull/2716
[#2717]: https://github.com/bytedance/deer-flow/pull/2717
[#2718]: https://github.com/bytedance/deer-flow/pull/2718
[#2725]: https://github.com/bytedance/deer-flow/pull/2725
[#2731]: https://github.com/bytedance/deer-flow/pull/2731
[#2740]: https://github.com/bytedance/deer-flow/pull/2740
[#2742]: https://github.com/bytedance/deer-flow/pull/2742
[#2752]: https://github.com/bytedance/deer-flow/pull/2752
[#2754]: https://github.com/bytedance/deer-flow/pull/2754
[#2757]: https://github.com/bytedance/deer-flow/pull/2757
[#2762]: https://github.com/bytedance/deer-flow/pull/2762
[#2766]: https://github.com/bytedance/deer-flow/pull/2766
[#2767]: https://github.com/bytedance/deer-flow/pull/2767
[#2770]: https://github.com/bytedance/deer-flow/pull/2770
[#2774]: https://github.com/bytedance/deer-flow/pull/2774
[#2775]: https://github.com/bytedance/deer-flow/pull/2775
[#2784]: https://github.com/bytedance/deer-flow/pull/2784
[#2794]: https://github.com/bytedance/deer-flow/pull/2794
[#2800]: https://github.com/bytedance/deer-flow/pull/2800
[#2822]: https://github.com/bytedance/deer-flow/pull/2822
[#2841]: https://github.com/bytedance/deer-flow/pull/2841
[#2842]: https://github.com/bytedance/deer-flow/pull/2842
[#2850]: https://github.com/bytedance/deer-flow/pull/2850
[#2861]: https://github.com/bytedance/deer-flow/pull/2861
[#2865]: https://github.com/bytedance/deer-flow/pull/2865
[#2867]: https://github.com/bytedance/deer-flow/pull/2867
[#2878]: https://github.com/bytedance/deer-flow/pull/2878
[#2881]: https://github.com/bytedance/deer-flow/pull/2881
[#2882]: https://github.com/bytedance/deer-flow/pull/2882
[#2885]: https://github.com/bytedance/deer-flow/pull/2885
[#2891]: https://github.com/bytedance/deer-flow/pull/2891
[#2907]: https://github.com/bytedance/deer-flow/pull/2907
[#2910]: https://github.com/bytedance/deer-flow/pull/2910
[#2915]: https://github.com/bytedance/deer-flow/pull/2915
[#2932]: https://github.com/bytedance/deer-flow/pull/2932
[#2933]: https://github.com/bytedance/deer-flow/pull/2933
[#2935]: https://github.com/bytedance/deer-flow/pull/2935
[#2936]: https://github.com/bytedance/deer-flow/pull/2936
[#2939]: https://github.com/bytedance/deer-flow/pull/2939
[#2940]: https://github.com/bytedance/deer-flow/pull/2940
[#2941]: https://github.com/bytedance/deer-flow/pull/2941
[#2944]: https://github.com/bytedance/deer-flow/pull/2944
[#2946]: https://github.com/bytedance/deer-flow/pull/2946
[#2954]: https://github.com/bytedance/deer-flow/pull/2954
[#2958]: https://github.com/bytedance/deer-flow/pull/2958
[#2962]: https://github.com/bytedance/deer-flow/pull/2962
[#2963]: https://github.com/bytedance/deer-flow/pull/2963
[#2973]: https://github.com/bytedance/deer-flow/pull/2973
[#2989]: https://github.com/bytedance/deer-flow/pull/2989
[#3002]: https://github.com/bytedance/deer-flow/pull/3002
[#3005]: https://github.com/bytedance/deer-flow/pull/3005
[#3033]: https://github.com/bytedance/deer-flow/pull/3033
[#3058]: https://github.com/bytedance/deer-flow/pull/3058
[#3069]: https://github.com/bytedance/deer-flow/pull/3069
[#3074]: https://github.com/bytedance/deer-flow/pull/3074
[#3101]: https://github.com/bytedance/deer-flow/pull/3101
[#3104]: https://github.com/bytedance/deer-flow/pull/3104
[#3130]: https://github.com/bytedance/deer-flow/pull/3130
[#3133]: https://github.com/bytedance/deer-flow/pull/3133
[#3144]: https://github.com/bytedance/deer-flow/pull/3144
[#3153]: https://github.com/bytedance/deer-flow/pull/3153
[#3174]: https://github.com/bytedance/deer-flow/pull/3174
[#3176]: https://github.com/bytedance/deer-flow/pull/3176
[#3191]: https://github.com/bytedance/deer-flow/pull/3191
[#3200]: https://github.com/bytedance/deer-flow/pull/3200
[#3228]: https://github.com/bytedance/deer-flow/pull/3228
[#3233]: https://github.com/bytedance/deer-flow/pull/3233
[#3241]: https://github.com/bytedance/deer-flow/pull/3241
[#3252]: https://github.com/bytedance/deer-flow/pull/3252
[#3270]: https://github.com/bytedance/deer-flow/pull/3270
[#3283]: https://github.com/bytedance/deer-flow/pull/3283
[#3284]: https://github.com/bytedance/deer-flow/pull/3284
[#3298]: https://github.com/bytedance/deer-flow/pull/3298
[#3301]: https://github.com/bytedance/deer-flow/pull/3301
[#3307]: https://github.com/bytedance/deer-flow/pull/3307
[#3311]: https://github.com/bytedance/deer-flow/pull/3311
[#3313]: https://github.com/bytedance/deer-flow/pull/3313
[#3335]: https://github.com/bytedance/deer-flow/pull/3335
[#3342]: https://github.com/bytedance/deer-flow/pull/3342
[#3377]: https://github.com/bytedance/deer-flow/pull/3377
[#3393]: https://github.com/bytedance/deer-flow/pull/3393
[#3397]: https://github.com/bytedance/deer-flow/pull/3397
[#3398]: https://github.com/bytedance/deer-flow/pull/3398
[#3408]: https://github.com/bytedance/deer-flow/pull/3408
[#3410]: https://github.com/bytedance/deer-flow/pull/3410
[#3411]: https://github.com/bytedance/deer-flow/pull/3411
[#3412]: https://github.com/bytedance/deer-flow/pull/3412
[#3413]: https://github.com/bytedance/deer-flow/pull/3413
[#3417]: https://github.com/bytedance/deer-flow/pull/3417
[#3421]: https://github.com/bytedance/deer-flow/pull/3421
[#3423]: https://github.com/bytedance/deer-flow/pull/3423
[#3425]: https://github.com/bytedance/deer-flow/pull/3425
[#3426]: https://github.com/bytedance/deer-flow/pull/3426
[#3428]: https://github.com/bytedance/deer-flow/pull/3428
[#3430]: https://github.com/bytedance/deer-flow/pull/3430
[#3433]: https://github.com/bytedance/deer-flow/pull/3433
[#3434]: https://github.com/bytedance/deer-flow/pull/3434
[#3435]: https://github.com/bytedance/deer-flow/pull/3435
[#3436]: https://github.com/bytedance/deer-flow/pull/3436
[#3437]: https://github.com/bytedance/deer-flow/pull/3437
[#3451]: https://github.com/bytedance/deer-flow/pull/3451
[#3453]: https://github.com/bytedance/deer-flow/pull/3453
[#3455]: https://github.com/bytedance/deer-flow/pull/3455
[#3457]: https://github.com/bytedance/deer-flow/pull/3457
[#3458]: https://github.com/bytedance/deer-flow/pull/3458
[#3460]: https://github.com/bytedance/deer-flow/pull/3460
[#3461]: https://github.com/bytedance/deer-flow/pull/3461
[#3464]: https://github.com/bytedance/deer-flow/pull/3464
[#3465]: https://github.com/bytedance/deer-flow/pull/3465
[#3466]: https://github.com/bytedance/deer-flow/pull/3466
[#3470]: https://github.com/bytedance/deer-flow/pull/3470
[#3471]: https://github.com/bytedance/deer-flow/pull/3471
[#3473]: https://github.com/bytedance/deer-flow/pull/3473
[#3475]: https://github.com/bytedance/deer-flow/pull/3475
[#3481]: https://github.com/bytedance/deer-flow/pull/3481
[#3485]: https://github.com/bytedance/deer-flow/pull/3485
[#3487]: https://github.com/bytedance/deer-flow/pull/3487
[#3488]: https://github.com/bytedance/deer-flow/pull/3488
[#3494]: https://github.com/bytedance/deer-flow/pull/3494
[#3495]: https://github.com/bytedance/deer-flow/pull/3495
[#3498]: https://github.com/bytedance/deer-flow/pull/3498
[#3499]: https://github.com/bytedance/deer-flow/pull/3499
[#3502]: https://github.com/bytedance/deer-flow/pull/3502
[#3503]: https://github.com/bytedance/deer-flow/pull/3503
[#3505]: https://github.com/bytedance/deer-flow/pull/3505
[#3506]: https://github.com/bytedance/deer-flow/pull/3506
[#3508]: https://github.com/bytedance/deer-flow/pull/3508
[#3512]: https://github.com/bytedance/deer-flow/pull/3512
[#3514]: https://github.com/bytedance/deer-flow/pull/3514
[#3517]: https://github.com/bytedance/deer-flow/pull/3517
[#3518]: https://github.com/bytedance/deer-flow/pull/3518
[#3519]: https://github.com/bytedance/deer-flow/pull/3519
[#3521]: https://github.com/bytedance/deer-flow/pull/3521
[#3526]: https://github.com/bytedance/deer-flow/pull/3526
[#3528]: https://github.com/bytedance/deer-flow/pull/3528
[#3530]: https://github.com/bytedance/deer-flow/pull/3530
[#3531]: https://github.com/bytedance/deer-flow/pull/3531
[#3533]: https://github.com/bytedance/deer-flow/pull/3533
[#3534]: https://github.com/bytedance/deer-flow/pull/3534
[#3535]: https://github.com/bytedance/deer-flow/pull/3535
[#3548]: https://github.com/bytedance/deer-flow/pull/3548
[#3551]: https://github.com/bytedance/deer-flow/pull/3551
[#3553]: https://github.com/bytedance/deer-flow/pull/3553
[#3554]: https://github.com/bytedance/deer-flow/pull/3554
[#3556]: https://github.com/bytedance/deer-flow/pull/3556
[#3557]: https://github.com/bytedance/deer-flow/pull/3557
[#3559]: https://github.com/bytedance/deer-flow/pull/3559
[#3561]: https://github.com/bytedance/deer-flow/pull/3561
[#3562]: https://github.com/bytedance/deer-flow/pull/3562
[#3563]: https://github.com/bytedance/deer-flow/pull/3563
[#3566]: https://github.com/bytedance/deer-flow/pull/3566
[#3569]: https://github.com/bytedance/deer-flow/pull/3569
[#3570]: https://github.com/bytedance/deer-flow/pull/3570
[#3573]: https://github.com/bytedance/deer-flow/pull/3573
[#3575]: https://github.com/bytedance/deer-flow/pull/3575
[#3577]: https://github.com/bytedance/deer-flow/pull/3577
[#3578]: https://github.com/bytedance/deer-flow/pull/3578
[#3579]: https://github.com/bytedance/deer-flow/pull/3579
[#3580]: https://github.com/bytedance/deer-flow/pull/3580
[#3581]: https://github.com/bytedance/deer-flow/pull/3581
[#3582]: https://github.com/bytedance/deer-flow/pull/3582
[#3583]: https://github.com/bytedance/deer-flow/pull/3583
[#3584]: https://github.com/bytedance/deer-flow/pull/3584
[#3585]: https://github.com/bytedance/deer-flow/pull/3585
[#3590]: https://github.com/bytedance/deer-flow/pull/3590
[#3591]: https://github.com/bytedance/deer-flow/pull/3591
[#3592]: https://github.com/bytedance/deer-flow/pull/3592
[#3599]: https://github.com/bytedance/deer-flow/pull/3599
[#3600]: https://github.com/bytedance/deer-flow/pull/3600
[#3601]: https://github.com/bytedance/deer-flow/pull/3601
[#3602]: https://github.com/bytedance/deer-flow/pull/3602
[#3605]: https://github.com/bytedance/deer-flow/pull/3605
[#3606]: https://github.com/bytedance/deer-flow/pull/3606
[#3608]: https://github.com/bytedance/deer-flow/pull/3608
[#3610]: https://github.com/bytedance/deer-flow/pull/3610
[#3611]: https://github.com/bytedance/deer-flow/pull/3611
[#3623]: https://github.com/bytedance/deer-flow/pull/3623
[#3624]: https://github.com/bytedance/deer-flow/pull/3624
[#3627]: https://github.com/bytedance/deer-flow/pull/3627
[#3629]: https://github.com/bytedance/deer-flow/pull/3629
[#3631]: https://github.com/bytedance/deer-flow/pull/3631
[#3637]: https://github.com/bytedance/deer-flow/pull/3637
[#3644]: https://github.com/bytedance/deer-flow/pull/3644
[#3646]: https://github.com/bytedance/deer-flow/pull/3646
[#3648]: https://github.com/bytedance/deer-flow/pull/3648
[#3649]: https://github.com/bytedance/deer-flow/pull/3649
[#3651]: https://github.com/bytedance/deer-flow/pull/3651
[#3654]: https://github.com/bytedance/deer-flow/pull/3654
[#3657]: https://github.com/bytedance/deer-flow/pull/3657
[#3658]: https://github.com/bytedance/deer-flow/pull/3658
[#3661]: https://github.com/bytedance/deer-flow/pull/3661
[#3662]: https://github.com/bytedance/deer-flow/pull/3662
[#3663]: https://github.com/bytedance/deer-flow/pull/3663
[#3665]: https://github.com/bytedance/deer-flow/pull/3665
[#3673]: https://github.com/bytedance/deer-flow/pull/3673
[#3674]: https://github.com/bytedance/deer-flow/pull/3674
[#3675]: https://github.com/bytedance/deer-flow/pull/3675
[#3685]: https://github.com/bytedance/deer-flow/pull/3685
[#3686]: https://github.com/bytedance/deer-flow/pull/3686
[#3687]: https://github.com/bytedance/deer-flow/pull/3687
[#3698]: https://github.com/bytedance/deer-flow/pull/3698
[#3709]: https://github.com/bytedance/deer-flow/pull/3709
[#3711]: https://github.com/bytedance/deer-flow/pull/3711
[#3713]: https://github.com/bytedance/deer-flow/pull/3713
[#3714]: https://github.com/bytedance/deer-flow/pull/3714
[#3718]: https://github.com/bytedance/deer-flow/pull/3718
[#3719]: https://github.com/bytedance/deer-flow/pull/3719
[#3729]: https://github.com/bytedance/deer-flow/pull/3729
[#3730]: https://github.com/bytedance/deer-flow/pull/3730
[#3733]: https://github.com/bytedance/deer-flow/pull/3733
[#3740]: https://github.com/bytedance/deer-flow/pull/3740
[#3753]: https://github.com/bytedance/deer-flow/pull/3753
[#3760]: https://github.com/bytedance/deer-flow/pull/3760
[#3764]: https://github.com/bytedance/deer-flow/pull/3764
[#3768]: https://github.com/bytedance/deer-flow/pull/3768
[#3769]: https://github.com/bytedance/deer-flow/pull/3769
[#3770]: https://github.com/bytedance/deer-flow/pull/3770
[#3772]: https://github.com/bytedance/deer-flow/pull/3772
[#3775]: https://github.com/bytedance/deer-flow/pull/3775
[#3786]: https://github.com/bytedance/deer-flow/pull/3786
[#3790]: https://github.com/bytedance/deer-flow/pull/3790
[#3791]: https://github.com/bytedance/deer-flow/pull/3791
[#3794]: https://github.com/bytedance/deer-flow/pull/3794
[#3797]: https://github.com/bytedance/deer-flow/pull/3797
[#3800]: https://github.com/bytedance/deer-flow/pull/3800
[#3809]: https://github.com/bytedance/deer-flow/pull/3809
[#3810]: https://github.com/bytedance/deer-flow/pull/3810
[#3812]: https://github.com/bytedance/deer-flow/pull/3812
[#3821]: https://github.com/bytedance/deer-flow/pull/3821
[#3826]: https://github.com/bytedance/deer-flow/pull/3826
[#3828]: https://github.com/bytedance/deer-flow/pull/3828
[#3837]: https://github.com/bytedance/deer-flow/pull/3837
[#3839]: https://github.com/bytedance/deer-flow/pull/3839
[#3843]: https://github.com/bytedance/deer-flow/pull/3843
[#3845]: https://github.com/bytedance/deer-flow/pull/3845
[#3854]: https://github.com/bytedance/deer-flow/pull/3854
[#3855]: https://github.com/bytedance/deer-flow/pull/3855
[#3856]: https://github.com/bytedance/deer-flow/pull/3856
[#3858]: https://github.com/bytedance/deer-flow/pull/3858
[#3860]: https://github.com/bytedance/deer-flow/pull/3860
[#3866]: https://github.com/bytedance/deer-flow/pull/3866
[#3869]: https://github.com/bytedance/deer-flow/pull/3869
[#3870]: https://github.com/bytedance/deer-flow/pull/3870
[#3871]: https://github.com/bytedance/deer-flow/pull/3871
[#3872]: https://github.com/bytedance/deer-flow/pull/3872
[#3874]: https://github.com/bytedance/deer-flow/pull/3874
[#3877]: https://github.com/bytedance/deer-flow/pull/3877
[#3878]: https://github.com/bytedance/deer-flow/pull/3878
[#3880]: https://github.com/bytedance/deer-flow/pull/3880
[#3881]: https://github.com/bytedance/deer-flow/pull/3881
[#3883]: https://github.com/bytedance/deer-flow/pull/3883
[#3885]: https://github.com/bytedance/deer-flow/pull/3885
[#3886]: https://github.com/bytedance/deer-flow/pull/3886
[#3887]: https://github.com/bytedance/deer-flow/pull/3887
[#3889]: https://github.com/bytedance/deer-flow/pull/3889
[#3897]: https://github.com/bytedance/deer-flow/pull/3897
[#3900]: https://github.com/bytedance/deer-flow/pull/3900
[#3902]: https://github.com/bytedance/deer-flow/pull/3902
[#3904]: https://github.com/bytedance/deer-flow/pull/3904
[#3906]: https://github.com/bytedance/deer-flow/pull/3906
[#3907]: https://github.com/bytedance/deer-flow/pull/3907
[#3908]: https://github.com/bytedance/deer-flow/pull/3908
[#3912]: https://github.com/bytedance/deer-flow/pull/3912
[#3917]: https://github.com/bytedance/deer-flow/pull/3917
[#3920]: https://github.com/bytedance/deer-flow/pull/3920
[#3924]: https://github.com/bytedance/deer-flow/pull/3924
[#3926]: https://github.com/bytedance/deer-flow/pull/3926
[#3927]: https://github.com/bytedance/deer-flow/pull/3927
[#3928]: https://github.com/bytedance/deer-flow/pull/3928
[#3931]: https://github.com/bytedance/deer-flow/pull/3931
[#3934]: https://github.com/bytedance/deer-flow/pull/3934
[#3935]: https://github.com/bytedance/deer-flow/pull/3935
[#3938]: https://github.com/bytedance/deer-flow/pull/3938
[#3940]: https://github.com/bytedance/deer-flow/pull/3940
[#3941]: https://github.com/bytedance/deer-flow/pull/3941
[#3942]: https://github.com/bytedance/deer-flow/pull/3942
[#3944]: https://github.com/bytedance/deer-flow/pull/3944
[#3945]: https://github.com/bytedance/deer-flow/pull/3945
[#3949]: https://github.com/bytedance/deer-flow/pull/3949
[#3950]: https://github.com/bytedance/deer-flow/pull/3950
[#3951]: https://github.com/bytedance/deer-flow/pull/3951
[#3956]: https://github.com/bytedance/deer-flow/pull/3956
[#3959]: https://github.com/bytedance/deer-flow/pull/3959
[#3961]: https://github.com/bytedance/deer-flow/pull/3961
[#3964]: https://github.com/bytedance/deer-flow/pull/3964
[#3966]: https://github.com/bytedance/deer-flow/pull/3966
[#3967]: https://github.com/bytedance/deer-flow/pull/3967
[#3969]: https://github.com/bytedance/deer-flow/pull/3969
[#3971]: https://github.com/bytedance/deer-flow/pull/3971
[#3976]: https://github.com/bytedance/deer-flow/pull/3976
[#3980]: https://github.com/bytedance/deer-flow/pull/3980
[#3981]: https://github.com/bytedance/deer-flow/pull/3981
[#3982]: https://github.com/bytedance/deer-flow/pull/3982
[#3985]: https://github.com/bytedance/deer-flow/pull/3985
[#3986]: https://github.com/bytedance/deer-flow/pull/3986
[#3988]: https://github.com/bytedance/deer-flow/pull/3988
[#3989]: https://github.com/bytedance/deer-flow/pull/3989
[#3990]: https://github.com/bytedance/deer-flow/pull/3990
[#3991]: https://github.com/bytedance/deer-flow/pull/3991
[#3992]: https://github.com/bytedance/deer-flow/pull/3992
[#3993]: https://github.com/bytedance/deer-flow/pull/3993
[#3994]: https://github.com/bytedance/deer-flow/pull/3994
[#3996]: https://github.com/bytedance/deer-flow/pull/3996
[#4003]: https://github.com/bytedance/deer-flow/pull/4003
[#4004]: https://github.com/bytedance/deer-flow/pull/4004
[#4008]: https://github.com/bytedance/deer-flow/pull/4008
[#4009]: https://github.com/bytedance/deer-flow/pull/4009
[#4012]: https://github.com/bytedance/deer-flow/pull/4012
[#4016]: https://github.com/bytedance/deer-flow/pull/4016
[#4017]: https://github.com/bytedance/deer-flow/pull/4017
[#4018]: https://github.com/bytedance/deer-flow/pull/4018
[#4023]: https://github.com/bytedance/deer-flow/pull/4023
[#4024]: https://github.com/bytedance/deer-flow/pull/4024
[#4026]: https://github.com/bytedance/deer-flow/pull/4026
[#4028]: https://github.com/bytedance/deer-flow/pull/4028
[#4033]: https://github.com/bytedance/deer-flow/pull/4033
[#4034]: https://github.com/bytedance/deer-flow/pull/4034
[#4035]: https://github.com/bytedance/deer-flow/pull/4035
[#4036]: https://github.com/bytedance/deer-flow/pull/4036
[#4038]: https://github.com/bytedance/deer-flow/pull/4038
[#4040]: https://github.com/bytedance/deer-flow/pull/4040
[#4051]: https://github.com/bytedance/deer-flow/pull/4051
[#4052]: https://github.com/bytedance/deer-flow/pull/4052
[#4053]: https://github.com/bytedance/deer-flow/pull/4053
[#4055]: https://github.com/bytedance/deer-flow/pull/4055
[#4058]: https://github.com/bytedance/deer-flow/pull/4058
[#4059]: https://github.com/bytedance/deer-flow/pull/4059
[#4060]: https://github.com/bytedance/deer-flow/pull/4060
[#4064]: https://github.com/bytedance/deer-flow/pull/4064
[#4065]: https://github.com/bytedance/deer-flow/pull/4065
[#4067]: https://github.com/bytedance/deer-flow/pull/4067
[#4069]: https://github.com/bytedance/deer-flow/pull/4069
[#4072]: https://github.com/bytedance/deer-flow/pull/4072
[#4073]: https://github.com/bytedance/deer-flow/pull/4073
[#4074]: https://github.com/bytedance/deer-flow/pull/4074
[#4076]: https://github.com/bytedance/deer-flow/pull/4076
[#4077]: https://github.com/bytedance/deer-flow/pull/4077
[#4078]: https://github.com/bytedance/deer-flow/pull/4078
[#4079]: https://github.com/bytedance/deer-flow/pull/4079
[#4080]: https://github.com/bytedance/deer-flow/pull/4080
[#4081]: https://github.com/bytedance/deer-flow/pull/4081
[#4082]: https://github.com/bytedance/deer-flow/pull/4082
[#4084]: https://github.com/bytedance/deer-flow/pull/4084
[#4085]: https://github.com/bytedance/deer-flow/pull/4085
[#4090]: https://github.com/bytedance/deer-flow/pull/4090
[#4094]: https://github.com/bytedance/deer-flow/pull/4094
[#4095]: https://github.com/bytedance/deer-flow/issues/4095
[#4096]: https://github.com/bytedance/deer-flow/pull/4096
[#4097]: https://github.com/bytedance/deer-flow/pull/4097
[#4098]: https://github.com/bytedance/deer-flow/pull/4098
[#4099]: https://github.com/bytedance/deer-flow/pull/4099
[#4100]: https://github.com/bytedance/deer-flow/pull/4100
[#4101]: https://github.com/bytedance/deer-flow/pull/4101
[#4102]: https://github.com/bytedance/deer-flow/pull/4102
[#4103]: https://github.com/bytedance/deer-flow/pull/4103
[#4104]: https://github.com/bytedance/deer-flow/pull/4104
[#4105]: https://github.com/bytedance/deer-flow/pull/4105
[#4108]: https://github.com/bytedance/deer-flow/pull/4108
[#4114]: https://github.com/bytedance/deer-flow/pull/4114
[#4115]: https://github.com/bytedance/deer-flow/pull/4115
[#4117]: https://github.com/bytedance/deer-flow/pull/4117
[#4118]: https://github.com/bytedance/deer-flow/pull/4118
[#4119]: https://github.com/bytedance/deer-flow/pull/4119
[#4122]: https://github.com/bytedance/deer-flow/pull/4122
[#4124]: https://github.com/bytedance/deer-flow/pull/4124
[#4128]: https://github.com/bytedance/deer-flow/pull/4128
[#4129]: https://github.com/bytedance/deer-flow/pull/4129
[#4130]: https://github.com/bytedance/deer-flow/pull/4130
[#4131]: https://github.com/bytedance/deer-flow/pull/4131
[#4133]: https://github.com/bytedance/deer-flow/pull/4133
[#4136]: https://github.com/bytedance/deer-flow/pull/4136
[#4137]: https://github.com/bytedance/deer-flow/pull/4137
[#4140]: https://github.com/bytedance/deer-flow/pull/4140
[#4141]: https://github.com/bytedance/deer-flow/pull/4141
[#4143]: https://github.com/bytedance/deer-flow/pull/4143
[#4146]: https://github.com/bytedance/deer-flow/pull/4146
[#4147]: https://github.com/bytedance/deer-flow/pull/4147
[#4154]: https://github.com/bytedance/deer-flow/pull/4154
[#4155]: https://github.com/bytedance/deer-flow/pull/4155
[#4157]: https://github.com/bytedance/deer-flow/pull/4157
[#4160]: https://github.com/bytedance/deer-flow/pull/4160
[#4161]: https://github.com/bytedance/deer-flow/pull/4161
[#4162]: https://github.com/bytedance/deer-flow/pull/4162
[#4166]: https://github.com/bytedance/deer-flow/pull/4166
[#4169]: https://github.com/bytedance/deer-flow/pull/4169
[#4170]: https://github.com/bytedance/deer-flow/pull/4170
[#4171]: https://github.com/bytedance/deer-flow/pull/4171
[#4174]: https://github.com/bytedance/deer-flow/pull/4174
[#4178]: https://github.com/bytedance/deer-flow/pull/4178
[#4181]: https://github.com/bytedance/deer-flow/pull/4181
[#4187]: https://github.com/bytedance/deer-flow/pull/4187
[#4188]: https://github.com/bytedance/deer-flow/pull/4188
[#4190]: https://github.com/bytedance/deer-flow/pull/4190
[#4192]: https://github.com/bytedance/deer-flow/issues/4192
[#4193]: https://github.com/bytedance/deer-flow/pull/4193
[#4197]: https://github.com/bytedance/deer-flow/pull/4197
[#4199]: https://github.com/bytedance/deer-flow/pull/4199
[#4202]: https://github.com/bytedance/deer-flow/pull/4202
[#4203]: https://github.com/bytedance/deer-flow/pull/4203
[#4208]: https://github.com/bytedance/deer-flow/pull/4208
[#4209]: https://github.com/bytedance/deer-flow/pull/4209
[#4215]: https://github.com/bytedance/deer-flow/pull/4215
[#4217]: https://github.com/bytedance/deer-flow/pull/4217
[#4218]: https://github.com/bytedance/deer-flow/pull/4218
[#4219]: https://github.com/bytedance/deer-flow/pull/4219
[#4222]: https://github.com/bytedance/deer-flow/pull/4222
[#4225]: https://github.com/bytedance/deer-flow/pull/4225
[#4229]: https://github.com/bytedance/deer-flow/pull/4229
[#4230]: https://github.com/bytedance/deer-flow/pull/4230
[#4234]: https://github.com/bytedance/deer-flow/pull/4234
[#4235]: https://github.com/bytedance/deer-flow/pull/4235
[#4238]: https://github.com/bytedance/deer-flow/pull/4238
[#4239]: https://github.com/bytedance/deer-flow/pull/4239
[#4245]: https://github.com/bytedance/deer-flow/pull/4245
[#4246]: https://github.com/bytedance/deer-flow/pull/4246
[#4251]: https://github.com/bytedance/deer-flow/pull/4251
[#4255]: https://github.com/bytedance/deer-flow/pull/4255
[#4256]: https://github.com/bytedance/deer-flow/pull/4256
[#4260]: https://github.com/bytedance/deer-flow/pull/4260
[#4264]: https://github.com/bytedance/deer-flow/pull/4264
[#4267]: https://github.com/bytedance/deer-flow/pull/4267
[#4268]: https://github.com/bytedance/deer-flow/pull/4268
[#4277]: https://github.com/bytedance/deer-flow/pull/4277
[#4278]: https://github.com/bytedance/deer-flow/pull/4278
[#4279]: https://github.com/bytedance/deer-flow/pull/4279
[#4283]: https://github.com/bytedance/deer-flow/pull/4283
[#4287]: https://github.com/bytedance/deer-flow/pull/4287
[#4288]: https://github.com/bytedance/deer-flow/pull/4288
[#4292]: https://github.com/bytedance/deer-flow/pull/4292
[#4306]: https://github.com/bytedance/deer-flow/pull/4306
[#4309]: https://github.com/bytedance/deer-flow/pull/4309
[#4311]: https://github.com/bytedance/deer-flow/pull/4311
[#4315]: https://github.com/bytedance/deer-flow/pull/4315
[#4316]: https://github.com/bytedance/deer-flow/pull/4316
[#4324]: https://github.com/bytedance/deer-flow/issues/4324
[#4326]: https://github.com/bytedance/deer-flow/pull/4326
[#4337]: https://github.com/bytedance/deer-flow/pull/4337
[#4347]: https://github.com/bytedance/deer-flow/pull/4347
[#4348]: https://github.com/bytedance/deer-flow/pull/4348
[#4354]: https://github.com/bytedance/deer-flow/pull/4354
[#4355]: https://github.com/bytedance/deer-flow/pull/4355
[#4356]: https://github.com/bytedance/deer-flow/pull/4356
[#4358]: https://github.com/bytedance/deer-flow/pull/4358
[#4361]: https://github.com/bytedance/deer-flow/pull/4361
[#4364]: https://github.com/bytedance/deer-flow/pull/4364
[#4365]: https://github.com/bytedance/deer-flow/pull/4365
[#4370]: https://github.com/bytedance/deer-flow/pull/4370
[#4371]: https://github.com/bytedance/deer-flow/pull/4371
[#4373]: https://github.com/bytedance/deer-flow/pull/4373
[#4374]: https://github.com/bytedance/deer-flow/pull/4374
[#4376]: https://github.com/bytedance/deer-flow/pull/4376
[#4381]: https://github.com/bytedance/deer-flow/pull/4381
[#4383]: https://github.com/bytedance/deer-flow/pull/4383
[#4385]: https://github.com/bytedance/deer-flow/pull/4385
[#4391]: https://github.com/bytedance/deer-flow/pull/4391
[#4392]: https://github.com/bytedance/deer-flow/pull/4392
[#4394]: https://github.com/bytedance/deer-flow/pull/4394
[#4402]: https://github.com/bytedance/deer-flow/pull/4402
[#4403]: https://github.com/bytedance/deer-flow/pull/4403
[#4407]: https://github.com/bytedance/deer-flow/pull/4407
[#4408]: https://github.com/bytedance/deer-flow/pull/4408
[#4411]: https://github.com/bytedance/deer-flow/pull/4411
[#4414]: https://github.com/bytedance/deer-flow/issues/4414
[#4424]: https://github.com/bytedance/deer-flow/issues/4424
[#4425]: https://github.com/bytedance/deer-flow/pull/4425
[#4426]: https://github.com/bytedance/deer-flow/pull/4426
[#4430]: https://github.com/bytedance/deer-flow/pull/4430
[#4431]: https://github.com/bytedance/deer-flow/pull/4431
[#4432]: https://github.com/bytedance/deer-flow/pull/4432
[#4434]: https://github.com/bytedance/deer-flow/pull/4434
[#4437]: https://github.com/bytedance/deer-flow/pull/4437
[#4441]: https://github.com/bytedance/deer-flow/pull/4441
[#4442]: https://github.com/bytedance/deer-flow/pull/4442
[#4444]: https://github.com/bytedance/deer-flow/pull/4444
[#4446]: https://github.com/bytedance/deer-flow/pull/4446
[#4447]: https://github.com/bytedance/deer-flow/pull/4447
[#4450]: https://github.com/bytedance/deer-flow/pull/4450
[#4456]: https://github.com/bytedance/deer-flow/pull/4456
[#4459]: https://github.com/bytedance/deer-flow/pull/4459
[#4460]: https://github.com/bytedance/deer-flow/pull/4460
[#4468]: https://github.com/bytedance/deer-flow/pull/4468
[#4469]: https://github.com/bytedance/deer-flow/pull/4469
[#4471]: https://github.com/bytedance/deer-flow/pull/4471
[#4516]: https://github.com/bytedance/deer-flow/pull/4516
[#4611]: https://github.com/bytedance/deer-flow/issues/4611
[#4745]: https://github.com/bytedance/deer-flow/pull/4745
[#4574]: https://github.com/bytedance/deer-flow/issues/4574
[#4577]: https://github.com/bytedance/deer-flow/pull/4577
[#4623]: https://github.com/bytedance/deer-flow/pull/4623
[#4634]: https://github.com/bytedance/deer-flow/pull/4634
[#4638]: https://github.com/bytedance/deer-flow/pull/4638
[#4848]: https://github.com/bytedance/deer-flow/pull/4848
[#3183]: https://github.com/bytedance/deer-flow/pull/3183
[#3396]: https://github.com/bytedance/deer-flow/pull/3396
[#3442]: https://github.com/bytedance/deer-flow/pull/3442
[#3565]: https://github.com/bytedance/deer-flow/pull/3565
[#3703]: https://github.com/bytedance/deer-flow/pull/3703
[#3708]: https://github.com/bytedance/deer-flow/pull/3708
[#3783]: https://github.com/bytedance/deer-flow/pull/3783
[#3824]: https://github.com/bytedance/deer-flow/pull/3824
[#3833]: https://github.com/bytedance/deer-flow/pull/3833
[#4025]: https://github.com/bytedance/deer-flow/pull/4025
[#4200]: https://github.com/bytedance/deer-flow/pull/4200
[#4210]: https://github.com/bytedance/deer-flow/pull/4210
[#4242]: https://github.com/bytedance/deer-flow/pull/4242
[#4247]: https://github.com/bytedance/deer-flow/pull/4247
[#4250]: https://github.com/bytedance/deer-flow/pull/4250
[#4262]: https://github.com/bytedance/deer-flow/pull/4262
[#4266]: https://github.com/bytedance/deer-flow/pull/4266
[#4274]: https://github.com/bytedance/deer-flow/pull/4274
[#4275]: https://github.com/bytedance/deer-flow/pull/4275
[#4284]: https://github.com/bytedance/deer-flow/pull/4284
[#4293]: https://github.com/bytedance/deer-flow/pull/4293
[#4298]: https://github.com/bytedance/deer-flow/pull/4298
[#4301]: https://github.com/bytedance/deer-flow/pull/4301
[#4302]: https://github.com/bytedance/deer-flow/pull/4302
[#4314]: https://github.com/bytedance/deer-flow/pull/4314
[#4360]: https://github.com/bytedance/deer-flow/pull/4360
[#4377]: https://github.com/bytedance/deer-flow/pull/4377
[#4382]: https://github.com/bytedance/deer-flow/pull/4382
[#4384]: https://github.com/bytedance/deer-flow/pull/4384
[#4395]: https://github.com/bytedance/deer-flow/pull/4395
[#4405]: https://github.com/bytedance/deer-flow/pull/4405
[#4406]: https://github.com/bytedance/deer-flow/pull/4406
[#4423]: https://github.com/bytedance/deer-flow/pull/4423
[#4427]: https://github.com/bytedance/deer-flow/pull/4427
[#4429]: https://github.com/bytedance/deer-flow/pull/4429
[#4439]: https://github.com/bytedance/deer-flow/pull/4439
[#4443]: https://github.com/bytedance/deer-flow/pull/4443
[#4448]: https://github.com/bytedance/deer-flow/pull/4448
[#4453]: https://github.com/bytedance/deer-flow/pull/4453
[#4472]: https://github.com/bytedance/deer-flow/pull/4472
[#4480]: https://github.com/bytedance/deer-flow/pull/4480
[#4482]: https://github.com/bytedance/deer-flow/pull/4482
[#4486]: https://github.com/bytedance/deer-flow/pull/4486
[#4489]: https://github.com/bytedance/deer-flow/pull/4489
[#4490]: https://github.com/bytedance/deer-flow/pull/4490
[#4493]: https://github.com/bytedance/deer-flow/pull/4493
[#4497]: https://github.com/bytedance/deer-flow/pull/4497
[#4500]: https://github.com/bytedance/deer-flow/pull/4500
[#4501]: https://github.com/bytedance/deer-flow/pull/4501
[#4504]: https://github.com/bytedance/deer-flow/pull/4504
[#4505]: https://github.com/bytedance/deer-flow/pull/4505
[#4506]: https://github.com/bytedance/deer-flow/pull/4506
[#4509]: https://github.com/bytedance/deer-flow/pull/4509
[#4510]: https://github.com/bytedance/deer-flow/pull/4510
[#4512]: https://github.com/bytedance/deer-flow/pull/4512
[#4513]: https://github.com/bytedance/deer-flow/pull/4513
[#4518]: https://github.com/bytedance/deer-flow/pull/4518
[#4519]: https://github.com/bytedance/deer-flow/pull/4519
[#4524]: https://github.com/bytedance/deer-flow/pull/4524
[#4527]: https://github.com/bytedance/deer-flow/pull/4527
[#4528]: https://github.com/bytedance/deer-flow/pull/4528
[#4530]: https://github.com/bytedance/deer-flow/pull/4530
[#4533]: https://github.com/bytedance/deer-flow/pull/4533
[#4534]: https://github.com/bytedance/deer-flow/pull/4534
[#4535]: https://github.com/bytedance/deer-flow/pull/4535
[#4538]: https://github.com/bytedance/deer-flow/pull/4538
[#4539]: https://github.com/bytedance/deer-flow/pull/4539
[#4540]: https://github.com/bytedance/deer-flow/pull/4540
[#4556]: https://github.com/bytedance/deer-flow/pull/4556
[#4558]: https://github.com/bytedance/deer-flow/pull/4558
[#4559]: https://github.com/bytedance/deer-flow/pull/4559
[#4564]: https://github.com/bytedance/deer-flow/pull/4564
[#4570]: https://github.com/bytedance/deer-flow/pull/4570
[#4575]: https://github.com/bytedance/deer-flow/pull/4575
[#4578]: https://github.com/bytedance/deer-flow/pull/4578
[#4582]: https://github.com/bytedance/deer-flow/pull/4582
[#4584]: https://github.com/bytedance/deer-flow/pull/4584
[#4587]: https://github.com/bytedance/deer-flow/pull/4587
[#4589]: https://github.com/bytedance/deer-flow/pull/4589
[#4590]: https://github.com/bytedance/deer-flow/pull/4590
[#4596]: https://github.com/bytedance/deer-flow/pull/4596
[#4599]: https://github.com/bytedance/deer-flow/pull/4599
[#4600]: https://github.com/bytedance/deer-flow/pull/4600
[#4604]: https://github.com/bytedance/deer-flow/pull/4604
[#4615]: https://github.com/bytedance/deer-flow/pull/4615
[#4617]: https://github.com/bytedance/deer-flow/pull/4617
[#4618]: https://github.com/bytedance/deer-flow/pull/4618
[#4620]: https://github.com/bytedance/deer-flow/pull/4620
[#4624]: https://github.com/bytedance/deer-flow/pull/4624
[#4625]: https://github.com/bytedance/deer-flow/pull/4625
[#4627]: https://github.com/bytedance/deer-flow/pull/4627
[#4629]: https://github.com/bytedance/deer-flow/pull/4629
[#4631]: https://github.com/bytedance/deer-flow/pull/4631
[#4633]: https://github.com/bytedance/deer-flow/pull/4633
[#4635]: https://github.com/bytedance/deer-flow/pull/4635
[#4636]: https://github.com/bytedance/deer-flow/pull/4636
[#4639]: https://github.com/bytedance/deer-flow/pull/4639
[#4643]: https://github.com/bytedance/deer-flow/pull/4643
[#4644]: https://github.com/bytedance/deer-flow/pull/4644
[#4647]: https://github.com/bytedance/deer-flow/pull/4647
[#4649]: https://github.com/bytedance/deer-flow/pull/4649
[#4657]: https://github.com/bytedance/deer-flow/pull/4657
[#4658]: https://github.com/bytedance/deer-flow/pull/4658
[#4659]: https://github.com/bytedance/deer-flow/pull/4659
[#4660]: https://github.com/bytedance/deer-flow/pull/4660
[#4665]: https://github.com/bytedance/deer-flow/pull/4665
[#4667]: https://github.com/bytedance/deer-flow/pull/4667
[#4668]: https://github.com/bytedance/deer-flow/pull/4668
[#4677]: https://github.com/bytedance/deer-flow/pull/4677
[#4681]: https://github.com/bytedance/deer-flow/pull/4681
[#4683]: https://github.com/bytedance/deer-flow/pull/4683
[#4684]: https://github.com/bytedance/deer-flow/pull/4684
[#4690]: https://github.com/bytedance/deer-flow/pull/4690
[#4693]: https://github.com/bytedance/deer-flow/pull/4693
[#4701]: https://github.com/bytedance/deer-flow/pull/4701
[#4703]: https://github.com/bytedance/deer-flow/pull/4703
[#4707]: https://github.com/bytedance/deer-flow/pull/4707
[#4709]: https://github.com/bytedance/deer-flow/pull/4709
[#4713]: https://github.com/bytedance/deer-flow/pull/4713
[#4719]: https://github.com/bytedance/deer-flow/pull/4719
[#4722]: https://github.com/bytedance/deer-flow/pull/4722
[#4724]: https://github.com/bytedance/deer-flow/pull/4724
[#4727]: https://github.com/bytedance/deer-flow/pull/4727
[#4730]: https://github.com/bytedance/deer-flow/pull/4730
[#4735]: https://github.com/bytedance/deer-flow/pull/4735
[#4736]: https://github.com/bytedance/deer-flow/pull/4736
[#4737]: https://github.com/bytedance/deer-flow/pull/4737
[#4738]: https://github.com/bytedance/deer-flow/pull/4738
[#4744]: https://github.com/bytedance/deer-flow/pull/4744
[#4747]: https://github.com/bytedance/deer-flow/pull/4747
[#4748]: https://github.com/bytedance/deer-flow/pull/4748
[#4750]: https://github.com/bytedance/deer-flow/pull/4750
[#4752]: https://github.com/bytedance/deer-flow/pull/4752
[#4755]: https://github.com/bytedance/deer-flow/pull/4755
[#4758]: https://github.com/bytedance/deer-flow/pull/4758
[#4759]: https://github.com/bytedance/deer-flow/pull/4759
[#4760]: https://github.com/bytedance/deer-flow/pull/4760
[#4762]: https://github.com/bytedance/deer-flow/pull/4762
[#4764]: https://github.com/bytedance/deer-flow/pull/4764
[#4767]: https://github.com/bytedance/deer-flow/pull/4767
[#4769]: https://github.com/bytedance/deer-flow/pull/4769
[#4772]: https://github.com/bytedance/deer-flow/pull/4772
[#4780]: https://github.com/bytedance/deer-flow/pull/4780
[#4783]: https://github.com/bytedance/deer-flow/pull/4783
[#4785]: https://github.com/bytedance/deer-flow/pull/4785
[#4789]: https://github.com/bytedance/deer-flow/pull/4789
[#4792]: https://github.com/bytedance/deer-flow/pull/4792
[#4797]: https://github.com/bytedance/deer-flow/pull/4797
[#4800]: https://github.com/bytedance/deer-flow/pull/4800
[#4804]: https://github.com/bytedance/deer-flow/pull/4804
[#4806]: https://github.com/bytedance/deer-flow/pull/4806
[#4812]: https://github.com/bytedance/deer-flow/pull/4812
[#4815]: https://github.com/bytedance/deer-flow/pull/4815
[#4816]: https://github.com/bytedance/deer-flow/pull/4816
[#4817]: https://github.com/bytedance/deer-flow/pull/4817
[#4822]: https://github.com/bytedance/deer-flow/pull/4822
[#4823]: https://github.com/bytedance/deer-flow/pull/4823
[#4825]: https://github.com/bytedance/deer-flow/pull/4825
[#4827]: https://github.com/bytedance/deer-flow/pull/4827
[#4830]: https://github.com/bytedance/deer-flow/pull/4830
[#4833]: https://github.com/bytedance/deer-flow/pull/4833
[#4836]: https://github.com/bytedance/deer-flow/pull/4836
[#4838]: https://github.com/bytedance/deer-flow/pull/4838
[#4840]: https://github.com/bytedance/deer-flow/pull/4840
[#4842]: https://github.com/bytedance/deer-flow/pull/4842
[#4844]: https://github.com/bytedance/deer-flow/pull/4844
[#4846]: https://github.com/bytedance/deer-flow/pull/4846
[#4852]: https://github.com/bytedance/deer-flow/pull/4852
[#4853]: https://github.com/bytedance/deer-flow/pull/4853
[#4860]: https://github.com/bytedance/deer-flow/pull/4860
[#4861]: https://github.com/bytedance/deer-flow/pull/4861
[#4863]: https://github.com/bytedance/deer-flow/pull/4863
[#4865]: https://github.com/bytedance/deer-flow/pull/4865
[#4868]: https://github.com/bytedance/deer-flow/pull/4868
[#4877]: https://github.com/bytedance/deer-flow/pull/4877
[#4882]: https://github.com/bytedance/deer-flow/pull/4882
[#4887]: https://github.com/bytedance/deer-flow/pull/4887
[#4888]: https://github.com/bytedance/deer-flow/pull/4888
[#4898]: https://github.com/bytedance/deer-flow/pull/4898
[#4903]: https://github.com/bytedance/deer-flow/pull/4903
[#4911]: https://github.com/bytedance/deer-flow/pull/4911
[#4918]: https://github.com/bytedance/deer-flow/pull/4918
[#4928]: https://github.com/bytedance/deer-flow/pull/4928
[#4933]: https://github.com/bytedance/deer-flow/pull/4933
[#4936]: https://github.com/bytedance/deer-flow/pull/4936
[#4938]: https://github.com/bytedance/deer-flow/pull/4938
[#4951]: https://github.com/bytedance/deer-flow/pull/4951
[#4953]: https://github.com/bytedance/deer-flow/pull/4953
[#4956]: https://github.com/bytedance/deer-flow/pull/4956
[#4959]: https://github.com/bytedance/deer-flow/pull/4959
[#4960]: https://github.com/bytedance/deer-flow/pull/4960
[#4963]: https://github.com/bytedance/deer-flow/pull/4963
[#4965]: https://github.com/bytedance/deer-flow/pull/4965
[#4970]: https://github.com/bytedance/deer-flow/pull/4970
[#4983]: https://github.com/bytedance/deer-flow/pull/4983
[#4987]: https://github.com/bytedance/deer-flow/pull/4987
[#4998]: https://github.com/bytedance/deer-flow/pull/4998
[#4696]: https://github.com/bytedance/deer-flow/pull/4696
[#4810]: https://github.com/bytedance/deer-flow/pull/4810
[#4820]: https://github.com/bytedance/deer-flow/pull/4820
[#4826]: https://github.com/bytedance/deer-flow/pull/4826
[#4834]: https://github.com/bytedance/deer-flow/pull/4834
[#4839]: https://github.com/bytedance/deer-flow/pull/4839
[#4867]: https://github.com/bytedance/deer-flow/pull/4867
[#4876]: https://github.com/bytedance/deer-flow/pull/4876
[#4878]: https://github.com/bytedance/deer-flow/pull/4878
[#4946]: https://github.com/bytedance/deer-flow/pull/4946
[#4955]: https://github.com/bytedance/deer-flow/pull/4955
[#4972]: https://github.com/bytedance/deer-flow/pull/4972
[#4977]: https://github.com/bytedance/deer-flow/pull/4977
[#4984]: https://github.com/bytedance/deer-flow/pull/4984
[#4986]: https://github.com/bytedance/deer-flow/pull/4986
[#5003]: https://github.com/bytedance/deer-flow/pull/5003
[#5006]: https://github.com/bytedance/deer-flow/pull/5006
[#5008]: https://github.com/bytedance/deer-flow/pull/5008
[#5010]: https://github.com/bytedance/deer-flow/pull/5010
[#5014]: https://github.com/bytedance/deer-flow/pull/5014
[#5017]: https://github.com/bytedance/deer-flow/pull/5017
[#5018]: https://github.com/bytedance/deer-flow/pull/5018
[#5021]: https://github.com/bytedance/deer-flow/pull/5021
[#5022]: https://github.com/bytedance/deer-flow/pull/5022
[#5023]: https://github.com/bytedance/deer-flow/pull/5023
[#5025]: https://github.com/bytedance/deer-flow/pull/5025
[#5027]: https://github.com/bytedance/deer-flow/pull/5027
[#5030]: https://github.com/bytedance/deer-flow/pull/5030
[#5031]: https://github.com/bytedance/deer-flow/pull/5031
[#5036]: https://github.com/bytedance/deer-flow/pull/5036
[#5039]: https://github.com/bytedance/deer-flow/pull/5039
[#5041]: https://github.com/bytedance/deer-flow/pull/5041
[#5045]: https://github.com/bytedance/deer-flow/pull/5045
[#5047]: https://github.com/bytedance/deer-flow/pull/5047
[#5049]: https://github.com/bytedance/deer-flow/pull/5049
[#5050]: https://github.com/bytedance/deer-flow/pull/5050
[#5051]: https://github.com/bytedance/deer-flow/pull/5051
[#5056]: https://github.com/bytedance/deer-flow/pull/5056
[#5057]: https://github.com/bytedance/deer-flow/pull/5057
[#5059]: https://github.com/bytedance/deer-flow/pull/5059
[#5064]: https://github.com/bytedance/deer-flow/pull/5064
[#5066]: https://github.com/bytedance/deer-flow/pull/5066
[#5069]: https://github.com/bytedance/deer-flow/pull/5069
[#5071]: https://github.com/bytedance/deer-flow/pull/5071
[#5074]: https://github.com/bytedance/deer-flow/pull/5074
[#5076]: https://github.com/bytedance/deer-flow/pull/5076
[#5077]: https://github.com/bytedance/deer-flow/pull/5077
[#5083]: https://github.com/bytedance/deer-flow/pull/5083
[#5086]: https://github.com/bytedance/deer-flow/pull/5086
[#5087]: https://github.com/bytedance/deer-flow/pull/5087
[#5089]: https://github.com/bytedance/deer-flow/pull/5089
[#5090]: https://github.com/bytedance/deer-flow/pull/5090
[#5092]: https://github.com/bytedance/deer-flow/pull/5092
[#5095]: https://github.com/bytedance/deer-flow/pull/5095
[#5099]: https://github.com/bytedance/deer-flow/pull/5099
[#5103]: https://github.com/bytedance/deer-flow/pull/5103
[#5105]: https://github.com/bytedance/deer-flow/pull/5105
[#5109]: https://github.com/bytedance/deer-flow/pull/5109
[#5112]: https://github.com/bytedance/deer-flow/pull/5112
[#5117]: https://github.com/bytedance/deer-flow/pull/5117
[#5133]: https://github.com/bytedance/deer-flow/pull/5133
[#5136]: https://github.com/bytedance/deer-flow/pull/5136
[#5239]: https://github.com/bytedance/deer-flow/pull/5239
[#5119]: https://github.com/bytedance/deer-flow/pull/5119
[#4726]: https://github.com/bytedance/deer-flow/pull/4726
[#4729]: https://github.com/bytedance/deer-flow/pull/4729
[#4884]: https://github.com/bytedance/deer-flow/pull/4884
[#4901]: https://github.com/bytedance/deer-flow/pull/4901
[#4944]: https://github.com/bytedance/deer-flow/pull/4944
[#4952]: https://github.com/bytedance/deer-flow/pull/4952
[#4980]: https://github.com/bytedance/deer-flow/pull/4980
[#4995]: https://github.com/bytedance/deer-flow/pull/4995
[#5026]: https://github.com/bytedance/deer-flow/pull/5026
[#5028]: https://github.com/bytedance/deer-flow/pull/5028
[#5062]: https://github.com/bytedance/deer-flow/pull/5062
[#5110]: https://github.com/bytedance/deer-flow/pull/5110
[#5111]: https://github.com/bytedance/deer-flow/pull/5111
[#5123]: https://github.com/bytedance/deer-flow/pull/5123
[#5134]: https://github.com/bytedance/deer-flow/pull/5134
[#5137]: https://github.com/bytedance/deer-flow/pull/5137
[#5141]: https://github.com/bytedance/deer-flow/pull/5141
[#5145]: https://github.com/bytedance/deer-flow/pull/5145
[#5149]: https://github.com/bytedance/deer-flow/pull/5149
[#5152]: https://github.com/bytedance/deer-flow/pull/5152
[#5153]: https://github.com/bytedance/deer-flow/pull/5153
[#5154]: https://github.com/bytedance/deer-flow/pull/5154
[#5155]: https://github.com/bytedance/deer-flow/pull/5155
[#5156]: https://github.com/bytedance/deer-flow/pull/5156
[#5159]: https://github.com/bytedance/deer-flow/pull/5159
[#5163]: https://github.com/bytedance/deer-flow/pull/5163
[#5164]: https://github.com/bytedance/deer-flow/pull/5164
[#5166]: https://github.com/bytedance/deer-flow/pull/5166
[#5168]: https://github.com/bytedance/deer-flow/pull/5168
[#5170]: https://github.com/bytedance/deer-flow/pull/5170
[#5181]: https://github.com/bytedance/deer-flow/pull/5181
[#5183]: https://github.com/bytedance/deer-flow/pull/5183
[#5185]: https://github.com/bytedance/deer-flow/pull/5185
[#5187]: https://github.com/bytedance/deer-flow/pull/5187
[#5191]: https://github.com/bytedance/deer-flow/pull/5191
[#5197]: https://github.com/bytedance/deer-flow/pull/5197
[#5206]: https://github.com/bytedance/deer-flow/pull/5206
[#5209]: https://github.com/bytedance/deer-flow/pull/5209
[#5219]: https://github.com/bytedance/deer-flow/pull/5219
[#5228]: https://github.com/bytedance/deer-flow/pull/5228
[#5232]: https://github.com/bytedance/deer-flow/pull/5232
[#5234]: https://github.com/bytedance/deer-flow/pull/5234
[#5236]: https://github.com/bytedance/deer-flow/pull/5236
[#5244]: https://github.com/bytedance/deer-flow/pull/5244
[#5245]: https://github.com/bytedance/deer-flow/pull/5245
[#5261]: https://github.com/bytedance/deer-flow/pull/5261
[#5265]: https://github.com/bytedance/deer-flow/pull/5265
[#5278]: https://github.com/bytedance/deer-flow/pull/5278
[#5280]: https://github.com/bytedance/deer-flow/pull/5280
[#5281]: https://github.com/bytedance/deer-flow/pull/5281
[#5282]: https://github.com/bytedance/deer-flow/pull/5282
[#5284]: https://github.com/bytedance/deer-flow/pull/5284
[#5287]: https://github.com/bytedance/deer-flow/pull/5287
[#5321]: https://github.com/bytedance/deer-flow/pull/5321
[#5338]: https://github.com/bytedance/deer-flow/pull/5338
[#5353]: https://github.com/bytedance/deer-flow/pull/5353
[#5357]: https://github.com/bytedance/deer-flow/pull/5357
[#5375]: https://github.com/bytedance/deer-flow/pull/5375
[#5393]: https://github.com/bytedance/deer-flow/pull/5393
[#5401]: https://github.com/bytedance/deer-flow/pull/5401
[#5403]: https://github.com/bytedance/deer-flow/pull/5403
[#5411]: https://github.com/bytedance/deer-flow/pull/5411