From de7307e6b3c8a4f8c8414c84c21bce34ee363da1 Mon Sep 17 00:00:00 2001 From: Willem Jiang Date: Wed, 21 Oct 2026 10:19:35 +0800 Subject: [PATCH] doc(changelog): update the changelog with the latest PR merged (#7222) * chore(doc):sync the chinese changelog info * chore(doc):sync the changelog with 2.2.0 milestone * chroe(doc):sync the Chinese changelog with the english one --- CHANGELOG.md | 1017 ++++++++++++++++++++++++++++++++++++++++- CHANGELOG_zh.md | 1144 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 2012 insertions(+), 149 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 171b088c85..fd3b93ef0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 This section accumulates work toward the **2.2.0** milestone ([2.2.0](https://github.com/bytedance/deer-flow/milestone/3)). -This release closes that milestone with **621 merged pull requests**. +As of 2026-10-21, the milestone includes **829 merged pull requests**. ### Added +- **mcp:** Cache fully wrapped tools per unchanged server, selectively + rediscovering only missing or changed configurations after binding + reconciliation. Preserve successful zero-tool results separately from failures + and retain generation, shared-reset and stdio-owner fencing. ([#6795]) + - **channels:** IM bot credentials entered in the web UI now live in the shared `channel_runtime_configs` table (migration `0044_channel_runtime_configs`) instead of each host's plaintext `channels/runtime-config.json`. Each @@ -585,6 +590,28 @@ This release closes that milestone with **621 merged pull requests**. #### Agents & runtime +- **context:** Accept bounded `context.client` names, capability flags and + preferences on Gateway run requests. The lead agent receives sanitized, + untrusted hints in a transient user-role `` block for choosing + output formats; hints do not grant permissions or persist into checkpoints + or run-config echoes. PII redaction applies when enabled. ([#7051]) + +- **sandbox:** Add default-off `sandbox.prewarm` for managed asynchronous AIO + runs and native subagents, overlapping authorized acquisition with the first + model response. Existing execution leases own and drain pending acquisition; + direct SDK graphs and other providers retain lazy behavior. Lifecycle + benchmarks now distinguish real resource cleanup and concurrent pressure + from successful measurements. ([#6998]) + +- **acceptance:** Add `file: csv-columns:["id","name"]` criteria for + delegated tasks and batches. Check exact required header names in any order + through authorized, bounded reads; malformed headers fail, unavailable or + incomplete evidence stays unverified, and data rows are not validated. ([#6714]) + +- **agents:** Add a configured tool-group catalog and tri-state Custom Agent + tool-access controls. Preserve unavailable selections for removal and submit + only edited fields to avoid overwriting concurrent settings changes. ([#6630]) + - **goal:** A met chat goal is now recorded on the thread, and the history head keeps goal state. When the evaluator finds a goal met, the checkpoint that clears it also writes a new `goal_outcome` channel: the objective, when @@ -845,6 +872,23 @@ This release closes that milestone with **621 merged pull requests**. #### Knowledge & retrieval +- **knowledge:** Add an independently installable, read-only WeKnora extension + using the shared catalog, scope, retrieval and citation pipeline. Explicit + endpoint/tenant and DeerFlow-user bindings constrain access; verified + evidence and document/base validation preserve attribution. Supports + WeKnora v0.8.3 without impersonating individual upstream users. ([#6950]) + +- **knowledge:** Decouple read-only provider catalogs and scope selection from + RAGFlow through extension API 0.2.7 provider registration, capability checks + and immutable run snapshots. Registered providers use the stable + `knowledge_search` interface and shared source artifacts. ([#6904]) + +- **knowledge:** Introduce provider-independent read-only retrieval results, + capabilities and shared source evidence. LightRAG and RAGFlow can use unified + citations while complete native RAGFlow snapshots remain compatible; + attribution survives budgets, delegation and replay, and caller-forged source + keys are stripped at Gateway boundaries. ([#6716]) + - **knowledge:** Custom-agent chats can scope RAGFlow retrieval per message. An opt-in Knowledge selector picks all operator-approved datasets, specific datasets/files, or no retrieval for one turn; the choice is stored as a @@ -901,6 +945,26 @@ This release closes that milestone with **621 merged pull requests**. #### Models & integrations +- **decisions:** Add an opt-in OpenAI Decisions backend for the existing tool + risk gate, memory pre-screen and signal-classification slots. Configure the + adapters through their existing `use:` paths with an explicit model; they + retain the current thresholds, failure policies, audit and bounded transport + behavior. ([#7127]) + +- **wizard:** Add an opt-in API Route gateway preset at + `https://global.api-route.com/v1`, using `API_ROUTE_API_KEY` and the existing + ChatOpenAI integration with a `gpt-6.1-sol` default. ([#6579]) + +- **models:** Register admin-managed models through provider presets, model + IDs and API keys, with optional custom endpoints and advanced capabilities. + Preserve encrypted credentials, config-defined names and optimistic revision + checks, and refresh chat and Agent pickers after changes. ([#6757]) + +- **serper:** Support `SERPER_BASE_URL` for compatible web and image search + endpoints, appending the original routes to the configured base and keeping + `SERPER_API_KEY`, payloads and result parsing unchanged. An unset or empty + override retains the existing endpoints. ([#6483]) + - **community:** New Unbrowse `web_fetch` provider - returns a page as markdown over plain HTTP, or through Unbrowse's hosted cloud browser for JavaScript-heavy pages (`render: auto|never|always`). One JSON-RPC POST per @@ -964,6 +1028,29 @@ This release closes that milestone with **621 merged pull requests**. #### Channels +- **channels:** Generalize explicit proactive group targets to Feishu, QQ and + WeCom, and add opt-in IM notices for ordinary web/background run completion, + terminal failure and human-input waits. Reuse owner preferences, bindings + and the notification outbox; runtime event toggles are off by default, goal + completion requires a satisfied verdict, and already-answered prompts are + dropped before sending. Personal WeChat delivery stays personal-only. + ([#6903]) + +- **channels:** Add shared notification preferences for connected Feishu, + WeCom, WeChat and QQ, plus proactive private WeChat/QQ delivery. Muting + cancels pending/retrying outbox rows atomically, and re-enabling does not + release the old backlog. WeChat requires valid owner/bot conversation context; + QQ delivery requires a non-empty platform message-ID acknowledgment. ([#6850]) + +- **feishu:** Let scheduled tasks explicitly select one additional bound group + for notifications through the existing outbox. Omitted destinations preserve + the selection, `null` clears it, and send-time ownership/binding checks do + not fall back to another group. ([#6762]) + +- **feishu:** Deliver scheduled results and lifecycle notices to bound users + as Markdown cards. Verified private-chat bindings supply the destination; + group or legacy chat IDs are not guessed into private recipients. ([#6753]) + - **channels:** IM channels can run on several Gateway instances. With `channels.leader_lease` active (`auto`, the default, follows the multi-process signal), each provider's platform connection belongs to the @@ -1076,6 +1163,43 @@ This release closes that milestone with **621 merged pull requests**. #### Extensions & plugins +- **workflows:** Add explicit, authenticated restart recovery for compatible + single-Gateway workflows. A persisted bridge journal replays confirmed + requests and results, rechecks session permissions and compatibility, and + requires reconciliation for uncertain child admissions instead of silently + dispatching them again. Recovery does not approve pending human output. ([#7075]) + +- **skills:** Add guarded evolution host APIs for trusted learning extensions, + including bounded completed-run evidence and source-bound skill mutation + capabilities in extension API 0.2.7. Explicit operator grants enable immutable + staging, validation, compare-and-swap publication, revert and crash recovery + for the body/description of existing enabled custom skills. Automatic + publication supports POSIX single-host local storage only; no learning + plugin or review UI is included. ([#5645]) + +- **workflows:** Add immutable named definitions, persisted owner approvals, + live-process human checkpoints and versioned artifact byte snapshots. + Preview, approval and downstream reads use the reviewed bytes, while + run-bound configuration evidence records actual Agent assembly without + exposing credentials or raw prompts. ([#6920]) + +- **workflows:** Add the default-disabled Script workflows extension for + sequencing, branching and bounded parallel Agent runs. A capability-restricted + QuickJS subprocess has no ambient credentials, filesystem or network access; + owner-scoped records and launch/inspect/cancel tools support the localized + workflow page and explicit reconciliation of uncertain admissions. ([#6858]) + +- **extensions:** Let ModelTool plugins opt into + `response_format="content_and_artifact"` with `PluginToolResult`, preserving + structured evidence separately from model-visible text. Validate and snapshot + content/artifact within one 64 KiB UTF-8 JSON limit while retaining default + JSON-return compatibility and host-bound identity. ([#6861]) + +- **extensions:** Add Agent Teams history pages, finished-result search and + bounded result reads that remain available after message rotation or service + restart. Owner-scoped, query-bound cursors and truncation provenance support + retrieval without admitting another Agent run. ([#6793]) + - **plugins:** Full-stack plugin APIs and a bookmark example package. A deployment-installed Python extension can now ship its own browser page, conversation actions and model tools: `registry.plugin(PluginContribution(...))` @@ -1263,8 +1387,638 @@ This release closes that milestone with **621 merged pull requests**. and the message toolbar also appears on keyboard focus. A `/goal` refused because a run is still going keeps the draft and says so. ([#6556]) +### Changed + +- **skills:** Treat `allowed-tools` as non-enforced compatibility metadata. + Activating a skill no longer hides or blocks tools that Agent configuration + and host authorization already permit, including when the declaration is + empty. Parsing, validation, export, skill-activation permissions and the + existing secret and user isolation boundaries are retained. ([#6935]) + ### Fixed +- **community:** Reject booleans in numeric LightRAG and RAGFlow + `knowledge_search` settings instead of silently treating `true` as a + one-second timeout, one result or one character of output. Invalid settings + return the existing configuration error. ([#7042]) + +- **uploads:** Keep filesystem operations and resource ownership together + across request cancellation. Staging, conversion, publication and remote + sync finish or reclaim their own resources before releasing the sandbox + lease, preventing orphaned files and cleanup races. ([#7170]) + +- **checkpoints:** Run conservative retention after successful completion, + before releasing the thread's finalizing barrier. Under the checkpoint + writer lock, remove at most one trailing duration-only leaf while preserving + ancestors, sibling branches and pending writes. ([#6051]) + +- **sandbox:** Measure warm-pool idle age with a monotonic clock across AIO, + BoxLite, E2B, OpenSandbox, Tenki and the shared lifecycle, including reset + paths, so wall-clock corrections neither reap fresh sandboxes nor retain + expired ones. Absolute creation timestamps remain wall-clock based. ([#7035]) + +- **goal:** Stop automatic continuations after a `loop_capped` hard stop, + preserving the active goal for a later user turn. The goal bar, scheduled + history and IM notices recognize the stop reason. ([#7167]) + +- **channels:** Make staged-file close, unlink and warning logging independent + best-effort cleanup steps in channel state, runtime credentials and WeChat + persistence. Cleanup failures no longer replace the original save error or + skip the remaining cleanup. ([#7106]) + +- **uploads:** Preserve separate bold spans in document-outline titles such + as `**Revenue** and **Profit**`, instead of mistaking them for a single + whole-title wrapper and leaving broken Markdown. ([#7150]) + +- **skills:** Escape backslashes, pipes and line breaks consistently in both + headers and values of data-analysis Markdown tables. CSV and JSON exports + retain their existing behavior. ([#7163]) + +- **helm:** Forward Live Browser WebSocket upgrades through a dedicated nginx + browser-stream location before the generic threads route, preserving + `Upgrade`/`Connection` headers and the long-running read timeout. ([#7148]) + +- **projects:** Preserve oversized-upload responses, publication errors and + recovery of already-committed shelf documents even when staging cleanup or + warning logging also fails. ([#7141]) + +- **memory:** Quarantine unreadable UTF-8 memory summaries before returning + from the read-error path, so a subsequent save cannot overwrite the only + copy of the original bytes. ([#7076]) + +- **tui:** Accept tabs and newlines between slash commands and their arguments. + Pasted skill tasks preserve their original indentation and line breaks, + while builtin precedence and reserved names are unchanged. ([#7117]) + +- **models:** Continue credential lookup after an unusable source. Blank + Claude environment tokens no longer hide valid file credentials, and an + invalid Codex token field no longer masks a usable alternate layout. ([#7140]) + +- **memory:** Preserve consecutive emergency pre-compaction snapshots in + arrival order while extraction is busy, instead of overwriting earlier + pending messages. Normal cumulative updates still coalesce. ([#7152]) + +- **codex:** Honor valid `retry-after-ms` and `Retry-After` hints in provider + retries. Invalid, non-finite or over-24-hour hints fall back to the existing + exponential schedule; retry statuses and attempt limits are unchanged. ([#7151]) + +- **frontend:** Restore thinking-only Anthropic steps behind their user + message after reconnect. Completed-answer boundaries now depend on visible + content rather than a non-empty content array. ([#7144]) + +- **storage:** Accept single-module `module:Class` custom blob-backend + selectors through the existing importer and subclass validation, matching + the already-supported dotted form. ([#7017]) + +- **docker:** Make the development Kubernetes provisioner opt-in through the + `provisioner` Compose profile. Docker wrappers enable it only for provisioner + sandbox mode and still remove it on stop. ([#6948]) + +- **skill-creator:** Validate optional timing documents and each token/duration + field independently. Malformed measurements warn and use existing fallbacks + without aborting a benchmark or discarding valid sibling measurements. ([#7078]) + +- **memory:** Read canonical fact Markdown with UTF-8 BOM support, so valid + hand-edited facts are not rejected as missing YAML front matter. ([#7116]) + +- **subagents:** Publish `TIMED_OUT` at the configured execution deadline even + when stream teardown resists cancellation. Keep cleanup supervised and + retain resource/capacity fences until teardown settles, while collecting + late token usage within the bounded tail window. ([#7053]) + +- **frontend:** Reject upload responses carrying `success: false` even when + HTTP status is 200. Chat sends stop and retain the draft and attachments + for retry instead of starting a run without the rejected file. ([#7122]) + +- **models:** Derive saved-key reuse from the current provider and endpoint, + so reverting a connection edit no longer sends an empty key or removes + stored credentials. Explicit key removal remains available. ([#6813]) + +- **browser:** Preserve the original capture publication error or interruption + when descriptor close, temporary-file removal or diagnostic logging also + fails. Cleanup steps remain independent and best-effort. ([#6871]) + +- **runtime:** Recover Redis SSE and `/wait` consumers after a producer dies + between durable terminal persistence and stream completion. Token-fenced + producer leases and a second empty heartbeat protect late tail frames. + Recovery is disabled by default behind the restart-required + `stream_bridge.producer_lease_recovery_enabled` gate; drain old writers and + pre-feature runs before enabling it across Gateways. ([#7093]) + +- **config:** Accept a leading UTF-8 BOM in operator-authored environment and + secret files, preserving valid variables and credentials without rewriting + the files or relaxing malformed-secret checks. ([#7112]) + +- **managed-models:** Map the generic `minimal` reasoning effort to `low` for + official DeepSeek endpoints and advertise their explicit supported efforts. + Third-party endpoint contracts retain their existing behavior. ([#6717]) + +- **streaming:** Replay retained successors when a Memory cursor is exactly + the known last-evicted event, avoiding a false replay gap. Unverifiable + cursors and genuinely missing successors still require gap recovery. ([#6812]) + +- **runtime:** Require attributable terminal-write acknowledgments before + publishing completion metadata, fence expired owners and isolate lease + renewal work per run. Blocked Store I/O can no longer starve other runs, + and late results cannot revive lost ownership. ([#6919]) + +- **memory:** Accept UTF-8 BOM-prefixed DeerMem summaries in both storage + implementations instead of reporting corruption or quarantining otherwise + valid JSON. Genuinely malformed summaries keep their existing handling. ([#7084]) + +- **github-research:** Resolve repository trees against `HEAD`, letting GitHub + select the actual default branch instead of falling back from `main` to a + potentially stale `master`. ([#7074]) + +- **frontend:** Cancel stale memory queries before caching successful create, + update, import, delete or clear results, preventing an older background + response from visually undoing a confirmed mutation. ([#6959]) + +- **mcp:** Treat a durable task's removed, disabled or otherwise unresolvable + server connection as a permanent failure, rather than indefinitely retrying + polling and cancellation against a connection that no longer exists. ([#7058]) + +- **frontend:** Retry failed Custom Agent setup saves and report creation + success only after a confirmed save and read-back. Exhausted retries restore + the idle Save state with localized error feedback. ([#6628]) + +- **skills:** Preserve data-analysis source identities across duplicate file + and sheet names, quoted paths, SQL rewriting and cached lookups. Valid SQL + literals, CTEs and aliases retain their meaning instead of being rewritten + as source-name substitutions. ([#6739]) + +- **workspace:** Skip files that disappear while being hashed and continue + the snapshot, retaining file-change recording and produced-output checks. + Permission and other I/O failures remain errors. ([#7057]) + +- **frontend:** Stop subtask-history pagination when a full page does not + advance the cursor, discarding that page while returning the valid prefix + already fetched instead of retrying or losing earlier steps. ([#6729]) + +- **frontend:** Keep Escape and Ctrl/Cmd+Enter with the IME during message-edit + composition, preventing accidental cancellation or submission. ([#6768]) + +- **crawl4ai:** Return a stable response-format error for non-object HTTP-200 + payloads and non-string Markdown fields instead of exposing raw Python + attribute errors. ([#7065]) + +- **skills:** Strip a leading UTF-8 BOM when reading `SKILL.md` for activation, + custom-skill read-back and assembly hashing, keeping model-visible content + and content fingerprints consistent with the parser. ([#6984]) + +- **memory:** Apply Honcho category filtering before the result limit instead + of labeling unfiltered hits with the requested category. ([#6981]) + +- **agents:** Strip a leading UTF-8 BOM from default and named-agent `SOUL.md` + files before inserting their contents into the system prompt. ([#7061]) + +- **memory:** Drop extracted facts with confidence outside `[0, 1]` at the + per-item normalization boundary, so one invalid score no longer fails the + complete update and repeatedly re-extracts the same messages. ([#6971]) + +- **sandbox:** Search long lines for literal `grep` patterns instead of + inheriting the regex long-line guard and returning false negatives. Existing + file, binary, symlink, summary and result limits still apply. ([#6969]) + +- **skill-creator:** Preserve recorded token counts, including zero, even + when grading already supplied a duration. Only missing or null token + measurements use the output-character fallback. ([#7033]) + +- **models:** Tolerate non-mapping `when_thinking_enabled.extra_body` values + on the reasoning-contract path instead of crashing every model construction + with an attribute error. ([#7039]) + +- **artifacts:** Preserve balanced ASCII `()`, `[]` and `{}` delimiters inside + captured paths and URLs while continuing to strip unmatched prose closers, + so persistent handles resolve to the original reference. ([#6967]) + +- **searxng:** Contain malformed HTTP-200 search payloads as format errors, + rather than raw Python exceptions or misleading empty-result responses. + Valid search results remain usable. ([#6931]) + +- **harness:** Scope deferred MCP schema promotion to the current genuine user + turn. A new turn re-defers earlier schemas while same-turn discovery, + execution, concurrent promotion merging and auditing remain consistent. ([#6977]) + +- **agents:** Clear an inherited `knowledge_scope` when a real tool-group + update removes knowledge access, preventing the next run from failing with + 422. Explicit API scope values and unrelated updates keep precedence. ([#6995]) + +- **runtime:** Persist the effective resolved model name for every run, + including default selections and fallbacks, and write only when the stored + name changes. Run history no longer retains a missing or merely requested + model name. ([#6980]) + +- **tencent-wsa:** Fall back to the default result count when a digit-like + configured string cannot be converted to an integer, while retaining valid + non-ASCII decimal counts. ([#6973]) + +- **scheduler:** Recheck lease liveness under the parent and occurrence locks + during expired-launch recovery. A fresh claim keeps its execution slot and + row state even if an earlier recovery scan observed it as expired. ([#6975]) + +- **sandbox:** Surface local `grep` sampling, open and read failures instead + of reporting unreadable text as no matches. Expected file disappearance + remains skippable; permission and other I/O failures become tool errors. ([#7004]) + +- **checkpoints:** Skip unserializable Redis history-cache entries individually + and continue writing valid neighbors. Optional caching no longer interrupts + authoritative history operations, and logs omit serializer exception text. + ([#7014]) + +- **frontend:** Preserve sanitized submitted input when the initial run stream + encounters a replay gap before its first durable checkpoint, merging it + with reloaded state through existing message-ID deduplication. ([#6800]) + +- **sandbox:** Retain generation-bound metadata and quarantine fences after + failed AIO teardown, confirm runtime absence before retiring records, and + preserve failed shutdown targets for retry instead of falsely reporting + successful destruction. Other resources still receive cleanup attempts. ([#7001]) + +- **streaming:** Retire Memory stream generations under their condition lock, + release retained payloads and wake unfinished readers with a replay-gap + signal. Cleanup no longer strands subscribers on detached buffers or lets + them follow a newly created generation. ([#6992]) + +- **runtime:** Bound force-close settlement of RunJournal progress snapshots + alongside event writes. Cancellation-resistant persistence remains + supervised without indefinitely blocking resource release or shutdown; + normal flushing retains its durability semantics. ([#6990]) + +- **skills:** Allow concurrent `skill_manage` callers on different event loops + to wake and serialize correctly, preventing sync-client and TUI hangs. + Waiting does not occupy executor workers, and cancelled waiters do not + leak ownership. ([#7020]) + +- **streaming:** Validate numeric reconnect cursors before subscription, + including integer-conversion failures and Redis's ASCII unsigned 64-bit + components. Oversized or invalid values follow the malformed-cursor policy + instead of terminating the subscription. ([#6690]) + +- **mcp:** Consume resolved or missing durable-task notification snapshots + before dispatch, so a recovered tracking condition no longer launches an + empty notification run or retries empty events until dead-lettering. ([#6693]) + +- **sandbox:** Translate every entry in colon-joined virtual path lists when + writing local files or shell commands, preserving usable PATH, PYTHONPATH + and custom-mount lists instead of translating only the first entry. ([#7002]) + +- **scripts:** Honor `DEER_FLOW_PROJECT_ROOT/config.yaml` when detecting + optional dependencies and admitting local startup, after an explicit + `DEER_FLOW_CONFIG_PATH`. External-project settings no longer lose required + extras or fail because the checkout lacks its own config. ([#6934]) + +- **github-research:** Encode raw repository-relative file paths once for + Contents API requests, preserving directory separators, percent signs, + query/fragment characters, spaces and Unicode with either HTTP backend. ([#7018]) + +- **uploads:** Offload document conversion for every source size instead of + using a compressed-size cutoff that lets small but expensive files block + the event loop. Conversion remains opt-in and cancellation still waits + for worker cleanup. ([#6924]) + +- **sandbox:** Preserve a concurrently written quarantine fence when retiring + an absent generation. A newly non-empty directory no longer aborts teardown + or removes another worker's protection. ([#6961]) + +- **tui:** Request cancellation of pending persistence work when the bridge + deadline expires, preventing an abandoned title update from continuing + unchecked. Cancellation remains cooperative and does not undo committed + writes. ([#6927]) + +- **infoquest:** Validate search response envelopes and result containers, + reporting malformed HTTP-200 payloads as format errors instead of Python + exceptions or an apparently successful empty search. ([#6932]) + +- **mcp:** Preserve remote URL bytes, including signed query strings and + fragments, during local-file result rewriting. Actual local paths and + `file:` references still translate under existing thread-root checks. ([#6878]) + +- **agents:** Preserve saved thinking and reasoning defaults when the model + catalog is loading, unavailable or missing the effective model, so an + unrelated settings edit cannot silently clear those overrides. ([#6907]) + +- **acceptance:** Recognize complete native Node TAP/spec summaries, requiring + an actual pass and prioritizing failures and cancellations. Empty, + all-skipped, all-todo and incomplete records remain unverified, including + colored Node 24 output. ([#6953]) + +- **streaming:** Signal a replay gap when an observed Redis stream disappears, + allowing SSE to reload durable state instead of heartbeating forever. + `/wait` refreshes persisted state before deciding that the run is complete. + ([#6951]) + +- **docker:** Treat omitted, blank, empty-quoted and YAML-null AIO provisioner + URLs consistently in both launchers, selecting local AIO and its socket + overlay instead of incorrectly starting the Kubernetes provisioner. ([#6945]) + +- **frontend:** Recognize a tab after a level-1 Markdown heading in fetched + content, displaying the document title instead of falling back to its URL. + Existing indentation and heading-level restrictions remain in place. ([#6923]) + +- **client:** Accumulate incremental streaming token usage per message and + reconcile completed snapshots without double counting. Terminal usage and + the TUI now match Gemini/vLLM usage-only chunks and input corrections. ([#6939]) + +- **summarization:** Consume all selected history from oldest to newest in + bounded chunks before compaction replaces it, including contiguous fragments + of oversized messages. Only generated summary carry may be shortened; + failed chunks, impossible budgets or the 64-chunk limit leave history intact. + ([#6918]) + +- **harness:** Apply the length-cap policy to Responses API + `incomplete`/`max_output_tokens` termination, including SSE. Suppress parsed + and native tool-call blocks while retaining text and reasoning, preventing + truncated calls from executing or replaying without tool outputs. ([#6946]) + +- **acceptance:** Keep all-skipped verbose Go test records unverified when + no passing case is present, rather than accepting `PASS` and package-level + `ok` banners as proof that a test ran successfully. ([#6957]) + +- **compaction:** Reject manual compaction with HTTP 409 when raw checkpoints + contain pending execution or cannot be inspected. Paused tool sends retain + their execution position instead of being lost in a new checkpoint. ([#6929]) + +- **e2b:** Pass literal grep patterns verbatim to `grep -F`, avoiding added + backslashes that turn punctuation and spaces into false negatives. Regex + patterns retain their existing validation. ([#6952]) + +- **runtime:** Defer host cancellation through every terminal-finalization + stage, including receipt/status persistence, completion hooks, extension + notifications and stream END. Propagate the cancellation after the required + terminal tail has settled. ([#6914]) + +- **runtime:** Normalize SQLAlchemy-style PostgreSQL DSNs before passing them + to synchronous checkpointers and sync/async stores, stripping `+driver` + suffixes even when no custom schema is configured. ([#6917]) + +- **acceptance:** Require a complete unittest count and success summary with + at least one ordinary pass. All-skipped or all-expected-failure suites and + isolated `OK` banners no longer satisfy `tests_passed` criteria. ([#6916]) + +- **search:** Surface DuckDuckGo dependency, transport and provider failures + as errors instead of `No results found`, allowing the agent to distinguish + an outage from a valid empty query. ([#6648]) + +- **community:** Reserve Browserless capture output names before publication, + so concurrent or same-second captures cannot silently overwrite each other + after both chose the same available filename. ([#6901]) + +- **subagents:** Renew durable batch leases throughout initialization, + execution and acceptance checking, and fence acknowledgments with each + claim's ownership generation. Atomic mutations prevent stale SQLite workers + or recovery scans from overwriting a newer attempt. ([#6764]) + +- **runtime:** Give RunJournal ownership of admitted event writes across + caller cancellation. Quarantine ambiguous commit outcomes instead of + retrying a possibly committed batch or allowing later events to overtake + it, preventing event loss and duplicate replay. ([#6846]) + +- **serper:** Report a response-format error when a non-empty web or image + result container contains no usable objects, rather than claiming the query + returned no results. Missing and genuinely empty lists remain empty. ([#6779]) + +- **opensandbox:** Report explicit command-deadline results with + `Exit Code: 124` while preserving partial stdout and stderr. Other missing + exit codes, signal-only statuses and transport failures keep their existing + reporting. ([#6885]) + +- **sandbox:** Shorten hashed quarantine path components to avoid Windows + `MAX_PATH` failures in deeply nested home and temporary directories. ([#6880]) + +- **uploads:** Skip malformed filenames and expected per-file probe failures, + and safely format oversized byte counts, so invalid attachment metadata + cannot abort a turn or suppress valid sibling uploads. ([#6882]) + +- **client:** Reconcile text appended before the first state snapshot, + emitting only the suffix beyond an already-streamed message. Middleware + additions now reach embedded `chat()` callers without duplicating text, + metadata or tool calls. ([#6910]) + +- **runtime:** Normalize supplied run-event timestamps to UTC before database + writes, preserving the same instant when SQLite discards timezone offsets. + Existing stored timestamps are not rewritten. ([#6894]) + +- **artifacts:** Supply authenticated static resource bytes to isolated HTML + previews, restoring sibling images, stylesheets, CSS imports and classic + scripts without granting the iframe same-origin access. ([#6701]) + +- **models:** Preserve Codex `tool_choice` through binding and direct + invocation, validating forced choices against available function tools + before HTTP dispatch. Valid `auto` and `none` remain usable without tools. + ([#6898]) + +- **models:** Default `gpt-6` family ChatOpenAI models to the Responses API + and `responses/v1` output, restoring tool calls with the pinned adapter. + Explicit operator API/output settings retain precedence. ([#6863]) + +- **knowledge:** Restrict RAGFlow-native citation cleanup to its own namespace, + preserving unified `#knowledge-source-...` links and evidence in mixed + delegated results through tool-output budgeting. ([#6886]) + +- **slack:** Accept user `file_share` events and file-only messages, and + download private attachments through the existing inbound-file pipeline. + Other message subtypes and bot messages remain excluded. ([#6855]) + +- **acceptance:** Recognize complete successful Cargo target summaries with + executed tests, so an empty sibling target no longer vetoes a passing one. + Bare success banners and all-empty or all-ignored runs remain unverified. + ([#6891]) + +- **serply:** Treat non-empty result containers with no usable objects as + format errors instead of reporting no search results. Missing or genuinely + empty containers retain their current behavior. ([#6796]) + +- **discord:** Admit file-only inbound messages, extract attachment + descriptors and download bounded CDN bytes through the shared ingestion + pipeline, preserving mention and thread gating. ([#6857]) + +- **mcp:** Evict only idle session owners under pool pressure, tracking active + calls by owner identity across ordinary tools and durable tasks. When every + session is busy, reject new acquisition or promotion rather than interrupting + an admitted call. ([#6900]) + +- **agents:** Capture standard top-level file/image URL content blocks as + persistent artifact handles, retaining legacy `source.url` support and + taking URL and MIME metadata from the same representation. ([#6893]) + +- **frontend:** Apply the scheduler's skipped/repeated-wall-time policy when + displaying saved one-time tasks across DST boundaries. New skipped-time + inputs remain invalid, and title-only edits preserve the saved instant. ([#6756]) + +- **subagents:** Require complete Maven or Gradle runner counters with at + least one non-skipped test for test acceptance. Build-success banners, + skipped tasks and incomplete counters no longer certify tests; reported + failures take precedence. ([#6868]) + +- **memory:** Retry transient Windows failures while opening the per-scope + lock file within the existing lock-acquisition deadline, avoiding errors + when concurrent callers first create it. ([#6870]) + +- **scripts:** Feed config-upgrade Python programs through stdin instead of + multiline argv, preventing Windows shim reparsing failures. Resolver probes + explicitly load the selected environment file before AppConfig. ([#6845]) + +- **tencent-wsa:** Report a format error when non-empty `Pages` contains no + usable page objects, preserving the distinction between malformed responses + and legitimate empty searches. ([#6799]) + +- **sandbox:** Append `Exit Code: 124` to E2B and BoxLite bash deadline errors, + giving the model and acceptance checker the same explicit timeout marker + used by other providers. ([#6848]) + +- **telegram:** Allow fresh replies and attachments in private chats when + their cached reply targets were deleted during a run. Working acknowledgments + and streaming previews use the same policy; group replies remain strict + to preserve forum routing. ([#6791]) + +- **view-image:** Bound re-injected context to four images and 28 MiB of + base64 data per model request, admitting recent images first and skipping + over-budget reads. Lightweight metadata and omission notices let the agent + re-view an older image without resending the thread's entire image history. + ([#6828], [#6829]) + +- **sandbox:** Restore persisted owner/thread workspace, uploads, outputs and + ACP files before exposing a newly created E2B sandbox. Active and warm + clients keep their live contents; failed or over-budget restoration fails + acquisition and cleans up the incomplete VM. ([#6824]) + +- **mindie:** Fall back to string rendering for unserializable tool arguments + during XML history replay, so a Python set or circular payload cannot make + every later request in the thread fail. ([#6839]) + +- **frontend:** Resolve local and document-relative images through the current + thread's artifact endpoint in Markdown panels and separate viewers. + Destinations refresh when file or thread context changes, while external + URLs and existing sanitization remain intact. ([#6827]) + +- **sandbox:** Report malformed AIO missing-file responses as an actionable + `file not found or unreadable` error instead of exposing SDK validation + details and encouraging repeated reads of a nonexistent file. ([#6834]) + +- **models:** Tolerate explicit null keys in legacy thinking-disable + templates, avoiding model-construction attribute errors for otherwise + accepted YAML profiles. ([#6838]) + +- **uploads:** Allow Windows replacement uploads despite NTFS's stale hard-link + counts, and identify published staging aliases by inode identity. First-claim + uploads and POSIX multi-link checks retain their strict guards. ([#6821]) + +- **auth:** Preserve existing encoded, blank and repeated OIDC authorization + endpoint query parameters when appending login parameters, including + discovered endpoints and configured overrides. ([#6831]) + +- **buzz:** Parse a scalar `allowed_users` pubkey as one member, validating + entries through the shared allowlist helper instead of iterating characters + or crashing on malformed scalars. Empty configurations remain deny-all. + ([#6811]) + +- **skills:** Require frontmatter `---` delimiters to occupy complete lines, + permitting only trailing spaces/tabs. Preserve instruction-body blank lines + and indentation after the closing delimiter. ([#6817]) + +- **sandbox:** Forward `sandbox.bash_command_timeout` to non-local command + execution instead of silently using remote-provider defaults. ([#6782]) + +- **sandbox:** Measure synchronous AIO readiness deadlines with a monotonic + clock, preventing wall-clock corrections from extending the wait or ending + it before a sandbox becomes ready. ([#6823]) + +- **telegram:** Drain interrupted bootstrap work through the shared cleanup + owner, stopping only running SDK components and closing partially initialized + Bot HTTP clients before the polling loop exits. Cancellation and timeout + leave cleanup available for retry. ([#6810]) + +- **wechat:** Use a dedicated 30-second QR-code status request timeout instead + of the generic 10-second timeout, preserving explicit caller overrides. + ([#6783]) + +- **extensions:** Hash Agent Teams result-cursor anchors independently of job + ID format, and project cancelled requests as unavailable answers rather + than searchable successful results. Cancellation notices remain in history. + ([#6832]) + +- **agents:** Measure LLM circuit-breaker recovery with a monotonic clock so + wall-clock changes cannot prolong or prematurely end the fast-fail window. + Absolute HTTP-date retry calculations remain wall-clock based. ([#6806]) + +- **loop-detection:** Let warn-level agents save collected results with a + file-writing tool before their final answer. Warnings target repeated + calls rather than banning all tools; thresholds and hard stops are unchanged. + ([#6804]) + +- **llm:** Retry streamed HTTP-200 responses that produce no generation chunk + through the existing transient-error backoff and budget, matching the + non-streaming empty-generation case. Other `ValueError`s remain generic. + ([#6803]) + +- **slack:** Retain executor-backed connect work through shutdown and await + it before closing the Socket Mode client off the event loop. A timed-out + or cancelled stop retains cleanup ownership for retry instead of permitting + a late connection to reopen the socket. ([#6808]) + +- **artifacts:** Keep unsaved artifact drafts for the application session, + scoped to account, conversation and path. Navigating to another thread or + workspace page and back no longer silently discards edits. ([#6700]) + +- **buzz:** Accept one `mention_free_channels` ID or a list, preventing scalar + strings from splitting into characters and numeric scalars from crashing + connector initialization. Blank values still grant no exemption. ([#6776]) + +- **browser:** Publish screenshots and Browserless capture/fetch outputs + through temporary files and atomic publication, avoiding partial captures + under final artifact names when writes fail. ([#6731]) + +- **runtime:** Reconstruct cached delta-history channel writes in canonical + task order while preserving each task's write sequence. Memory-checkpointer + history no longer changes with cache warmth after fan-out steps. ([#6774]) + +- **telegram:** Retain a single polling-loop cleanup operation across bounded + stops and caller cancellation. Retried stops join that owner instead of + cancelling cleanup, closing the loop early or racing another teardown. + ([#6772]) + +- **frontend:** Place the caret immediately after an inserted composer + reference, preventing immediate typing from appearing before it or a late + animation-frame callback from overriding a user cursor move. ([#6762]) + +- **extensions:** Isolate Agent Teams execution/control locks and background + workers per team, keeping slow host calls out of the scheduling lock. + Rotate admission attempts by owner and reserve slots before dispatch so + unrelated teams remain responsive and new work receives fair access. ([#6754]) + +- **memory:** Search the complete fact scope in the substring fallback instead + of only the first default 100-item page, so matching facts beyond that page + remain discoverable when indexed retrieval is disabled. ([#6732]) + +- **memory:** Preserve free-form fact categories instead of rewriting non-core + labels to `other`, restoring exact category search and read-back for labels + such as `personal` and extracted `knowledge`. ([#6733]) + +- **opensandbox:** Mirror regular thread output files into the owner's local + artifact directory before warm parking, making presented reports downloadable + through Gateway instead of returning 404 for remote-only files. ([#6699]) + +- **sandbox:** Apply the host-locale decoding fallback to native-child output + under PowerShell, preserving non-ASCII tool results on Windows code pages + while keeping valid UTF-8 output unchanged. ([#6727]) + +- **sofya:** Report format errors for non-empty result lists without usable + objects rather than treating malformed search/fetch responses as no results. + ([#6719]) + +- **dingtalk:** Split Markdown fallback tables only on unescaped pipes and + remove at most one outer border cell per side. Escaped separators and empty + edge cells no longer shift values under the wrong labels. ([#6741]) + +- **frontend:** Preserve the current preset cadence when switching to Custom + cron, including weekdays and month days, and reflect subsequent preset edits + instead of restoring a stale custom expression. ([#6749]) + +- **agents:** Allow SQL-backed Custom Agent updates while retained legacy + files remain for rollback. Apply the legacy-layout guard only to file-backed + stores, keeping both HTTP and tool updates consistent. ([#6747]) + - **memory:** DeerMem no longer sends conversation turns it already extracted to the memory LLM again when a thread's next turn runs on another Gateway instance or after a restart. The extraction watermark (the last message of @@ -1343,7 +2097,7 @@ This release closes that milestone with **621 merged pull requests**. and the supervisor then waits on the pending calls locally (still checking cancellation, faults and worker exits every 20 ms) without exchanging frames, so idle waits no longer consume turns and `timeout_seconds` is the only wall-clock bound; - scripts that spin the job queue still hit the turn cap. (issue #7022) + scripts that spin the job queue still hit the turn cap. (issue #7022, [#7024]) - **browser:** `browser_screenshot` no longer replaces a file that already exists in the thread's outputs directory. A screenshot saved as `report.png` used to overwrite the user's own `report.png`, an earlier @@ -6111,7 +6865,7 @@ This release closes that milestone with **621 merged pull requests**. to syntax the scanner does not model (a backslash-newline, backticks, `$'...'`, an unmatched `)`), nor to a program whose `"` may sit in an awk regex literal; `/` and `#` inside an awk string literal are plain text. - (issue #7021) + (issue #7021, [#7023]) - **sandbox:** On the local sandbox, `ls` now accepts the `/mnt/user-data` root itself and lists `workspace`, `uploads` and `outputs` as it does on AIO. The provider maps that root on purpose, but the tool layer allowed @@ -6123,6 +6877,41 @@ This release closes that milestone with **621 merged pull requests**. ### Security +- **infoquest:** Screen organic, news and image result URLs through the shared + public-URL policy, dropping non-public and unsafe references before they + reach the model. ([#7031]) + +- **checkpoints:** Escape Redis glob metacharacters when purging a literal + thread namespace, and verify scanned keys against that literal stem before + deletion. Custom prefixes can no longer delete another namespace's cache. + ([#6709]) + +- **channels:** Parse Slack and DingTalk `allowed_users` through the shared + fail-closed helper. Invalid or empty configured entries no longer silently + disable access restrictions, and padded IDs are normalized. ([#6742]) + +- **image-search:** Normalize Unicode hostname dot separators before shared + address checks, rejecting disguised loopback, private, metadata and other + blocked literal hosts while preserving accepted URL spelling. ([#6819]) + +- **mcp:** Omit credential-bearing exception messages and tracebacks from + discovery error logs, retaining server names and exception types without + changing discovery failure handling. ([#6794]) + +- **image-search:** Share public result-URL screening across DuckDuckGo, + Brave and Serper, including thumbnail fallback and embedded IPv4 checks. + Reject blocked literal addresses such as multicast and NAT64 loopback; + this string-only screening does not resolve DNS. ([#6740]) + +- **qq:** Parse scalar and collection `allowed_users` through the shared + fail-closed helper, avoiding character-wise IDs, mapping-key authorization + and permissive fallback from invalid configured restrictions. ([#6730]) + +- **frontend:** Accept only own keys of the structured subagent-status map. + Unknown prototype names such as `constructor` and `__proto__` now use the + existing in-progress fallback without attaching result/error metadata. + ([#6669]) + - **skills:** `GET /api/skills`, `GET /api/skills/custom` and `GET /api/skills/{name}`, which every signed-in user can call, no longer put the raw exception text in their `500` detail. A malformed or unreadable @@ -6524,6 +7313,12 @@ This release closes that milestone with **621 merged pull requests**. ### Documentation +- **extensions:** Add an example-authoring and packaging guide plus + `scripts/check_extension.py PACKAGE`, which builds a temporary wheel and + checks entry points, Python syntax, API dependency compatibility and browser + assets before installation. The checker runs trusted build backends without + importing the extension or changing deployment configuration. ([#6755]) + - **docs:** Add a Korean README (`README_ko.md`), a complete translation of the current English README. Headings, tables, and links mirror the English one-to-one, and every code block and inline code span stays byte-identical; @@ -6674,6 +7469,36 @@ This release closes that milestone with **621 merged pull requests**. ### Internal +- **frontend:** Remove the deprecated, unused `hast` and `@types/gsap` + packages. Existing `@types/hast` and GSAP's bundled types continue to supply + the required declarations. ([#7108]) + +- **tests:** Skip POSIX-only skill mutation cases on Windows while retaining + portable coverage, and release a pooled SQLite fixture connection before + the database-removal test. ([#7154]) + +- **benchmarks:** Add opt-in OpenSandbox coverage to the standalone sandbox + benchmark, using the production provider for cold/warm reuse, replica + pressure and idle reaping. Cleanup failures produce failed shutdown evidence + instead of a successful benchmark summary. ([#7059]) + +- **tests:** Pass an allowlist of base Windows system and temporary-directory + environment variables to the isolated live-policy pytest child, allowing + interpreter initialization while retaining credential isolation. ([#6439]) + +- **tests:** Repair six Windows-host fixture and assertion failures across + command execution, binary reads, Lark file modes, skill review and extension + archive checks while preserving the underlying behavior contracts. ([#6787]) + +- **ci:** Run the unified extension packaging checker on every bundled example + when relevant examples, host code, dependencies, checker or workflow changes, + exercising the actual wheel and browser assets. ([#6788]) + +- **mcp:** Expose server-scoped discovery results with fully wrapped tool + groups and stdio binding ownership. Preserve the existing ordered flattened + public API and distinguish successful zero-tool discovery from failure, + providing the prerequisite for selective caching. ([#6734]) + - **deps:** Bump `lark-oapi` from 1.5.5 to 1.7.3 in `/backend`. ([#6665]) - **models:** Give reasoning capture a single owner. The byte-identical @@ -11933,3 +12758,189 @@ with **180 merged pull requests** since the first 2.0 milestone tag. [#7123]: https://github.com/bytedance/deer-flow/pull/7123 [#7155]: https://github.com/bytedance/deer-flow/pull/7155 [#7205]: https://github.com/bytedance/deer-flow/pull/7205 +[#5645]: https://github.com/bytedance/deer-flow/pull/5645 +[#6051]: https://github.com/bytedance/deer-flow/pull/6051 +[#6439]: https://github.com/bytedance/deer-flow/pull/6439 +[#6483]: https://github.com/bytedance/deer-flow/pull/6483 +[#6579]: https://github.com/bytedance/deer-flow/pull/6579 +[#6628]: https://github.com/bytedance/deer-flow/pull/6628 +[#6630]: https://github.com/bytedance/deer-flow/pull/6630 +[#6648]: https://github.com/bytedance/deer-flow/pull/6648 +[#6669]: https://github.com/bytedance/deer-flow/pull/6669 +[#6690]: https://github.com/bytedance/deer-flow/pull/6690 +[#6693]: https://github.com/bytedance/deer-flow/pull/6693 +[#6699]: https://github.com/bytedance/deer-flow/pull/6699 +[#6700]: https://github.com/bytedance/deer-flow/pull/6700 +[#6701]: https://github.com/bytedance/deer-flow/pull/6701 +[#6709]: https://github.com/bytedance/deer-flow/pull/6709 +[#6714]: https://github.com/bytedance/deer-flow/pull/6714 +[#6716]: https://github.com/bytedance/deer-flow/pull/6716 +[#6717]: https://github.com/bytedance/deer-flow/pull/6717 +[#6719]: https://github.com/bytedance/deer-flow/pull/6719 +[#6727]: https://github.com/bytedance/deer-flow/pull/6727 +[#6729]: https://github.com/bytedance/deer-flow/pull/6729 +[#6730]: https://github.com/bytedance/deer-flow/pull/6730 +[#6731]: https://github.com/bytedance/deer-flow/pull/6731 +[#6732]: https://github.com/bytedance/deer-flow/pull/6732 +[#6733]: https://github.com/bytedance/deer-flow/pull/6733 +[#6734]: https://github.com/bytedance/deer-flow/pull/6734 +[#6739]: https://github.com/bytedance/deer-flow/pull/6739 +[#6740]: https://github.com/bytedance/deer-flow/pull/6740 +[#6741]: https://github.com/bytedance/deer-flow/pull/6741 +[#6742]: https://github.com/bytedance/deer-flow/pull/6742 +[#6747]: https://github.com/bytedance/deer-flow/pull/6747 +[#6749]: https://github.com/bytedance/deer-flow/pull/6749 +[#6753]: https://github.com/bytedance/deer-flow/pull/6753 +[#6754]: https://github.com/bytedance/deer-flow/pull/6754 +[#6755]: https://github.com/bytedance/deer-flow/pull/6755 +[#6756]: https://github.com/bytedance/deer-flow/pull/6756 +[#6757]: https://github.com/bytedance/deer-flow/pull/6757 +[#6762]: https://github.com/bytedance/deer-flow/pull/6762 +[#6764]: https://github.com/bytedance/deer-flow/pull/6764 +[#6768]: https://github.com/bytedance/deer-flow/pull/6768 +[#6772]: https://github.com/bytedance/deer-flow/pull/6772 +[#6774]: https://github.com/bytedance/deer-flow/pull/6774 +[#6776]: https://github.com/bytedance/deer-flow/pull/6776 +[#6779]: https://github.com/bytedance/deer-flow/pull/6779 +[#6782]: https://github.com/bytedance/deer-flow/pull/6782 +[#6783]: https://github.com/bytedance/deer-flow/pull/6783 +[#6787]: https://github.com/bytedance/deer-flow/pull/6787 +[#6788]: https://github.com/bytedance/deer-flow/pull/6788 +[#6791]: https://github.com/bytedance/deer-flow/pull/6791 +[#6793]: https://github.com/bytedance/deer-flow/pull/6793 +[#6794]: https://github.com/bytedance/deer-flow/pull/6794 +[#6795]: https://github.com/bytedance/deer-flow/pull/6795 +[#6796]: https://github.com/bytedance/deer-flow/pull/6796 +[#6799]: https://github.com/bytedance/deer-flow/pull/6799 +[#6800]: https://github.com/bytedance/deer-flow/pull/6800 +[#6803]: https://github.com/bytedance/deer-flow/pull/6803 +[#6804]: https://github.com/bytedance/deer-flow/pull/6804 +[#6806]: https://github.com/bytedance/deer-flow/pull/6806 +[#6808]: https://github.com/bytedance/deer-flow/pull/6808 +[#6810]: https://github.com/bytedance/deer-flow/pull/6810 +[#6811]: https://github.com/bytedance/deer-flow/pull/6811 +[#6812]: https://github.com/bytedance/deer-flow/pull/6812 +[#6813]: https://github.com/bytedance/deer-flow/pull/6813 +[#6817]: https://github.com/bytedance/deer-flow/pull/6817 +[#6819]: https://github.com/bytedance/deer-flow/pull/6819 +[#6821]: https://github.com/bytedance/deer-flow/pull/6821 +[#6823]: https://github.com/bytedance/deer-flow/pull/6823 +[#6824]: https://github.com/bytedance/deer-flow/pull/6824 +[#6827]: https://github.com/bytedance/deer-flow/pull/6827 +[#6828]: https://github.com/bytedance/deer-flow/pull/6828 +[#6829]: https://github.com/bytedance/deer-flow/pull/6829 +[#6831]: https://github.com/bytedance/deer-flow/pull/6831 +[#6832]: https://github.com/bytedance/deer-flow/pull/6832 +[#6834]: https://github.com/bytedance/deer-flow/pull/6834 +[#6838]: https://github.com/bytedance/deer-flow/pull/6838 +[#6839]: https://github.com/bytedance/deer-flow/pull/6839 +[#6845]: https://github.com/bytedance/deer-flow/pull/6845 +[#6846]: https://github.com/bytedance/deer-flow/pull/6846 +[#6848]: https://github.com/bytedance/deer-flow/pull/6848 +[#6850]: https://github.com/bytedance/deer-flow/pull/6850 +[#6855]: https://github.com/bytedance/deer-flow/pull/6855 +[#6857]: https://github.com/bytedance/deer-flow/pull/6857 +[#6858]: https://github.com/bytedance/deer-flow/pull/6858 +[#6861]: https://github.com/bytedance/deer-flow/pull/6861 +[#6863]: https://github.com/bytedance/deer-flow/pull/6863 +[#6868]: https://github.com/bytedance/deer-flow/pull/6868 +[#6870]: https://github.com/bytedance/deer-flow/pull/6870 +[#6871]: https://github.com/bytedance/deer-flow/pull/6871 +[#6878]: https://github.com/bytedance/deer-flow/pull/6878 +[#6880]: https://github.com/bytedance/deer-flow/pull/6880 +[#6882]: https://github.com/bytedance/deer-flow/pull/6882 +[#6885]: https://github.com/bytedance/deer-flow/pull/6885 +[#6886]: https://github.com/bytedance/deer-flow/pull/6886 +[#6891]: https://github.com/bytedance/deer-flow/pull/6891 +[#6893]: https://github.com/bytedance/deer-flow/pull/6893 +[#6894]: https://github.com/bytedance/deer-flow/pull/6894 +[#6898]: https://github.com/bytedance/deer-flow/pull/6898 +[#6900]: https://github.com/bytedance/deer-flow/pull/6900 +[#6901]: https://github.com/bytedance/deer-flow/pull/6901 +[#6903]: https://github.com/bytedance/deer-flow/pull/6903 +[#6904]: https://github.com/bytedance/deer-flow/pull/6904 +[#6907]: https://github.com/bytedance/deer-flow/pull/6907 +[#6910]: https://github.com/bytedance/deer-flow/pull/6910 +[#6914]: https://github.com/bytedance/deer-flow/pull/6914 +[#6916]: https://github.com/bytedance/deer-flow/pull/6916 +[#6917]: https://github.com/bytedance/deer-flow/pull/6917 +[#6918]: https://github.com/bytedance/deer-flow/pull/6918 +[#6919]: https://github.com/bytedance/deer-flow/pull/6919 +[#6920]: https://github.com/bytedance/deer-flow/pull/6920 +[#6923]: https://github.com/bytedance/deer-flow/pull/6923 +[#6924]: https://github.com/bytedance/deer-flow/pull/6924 +[#6927]: https://github.com/bytedance/deer-flow/pull/6927 +[#6929]: https://github.com/bytedance/deer-flow/pull/6929 +[#6931]: https://github.com/bytedance/deer-flow/pull/6931 +[#6932]: https://github.com/bytedance/deer-flow/pull/6932 +[#6934]: https://github.com/bytedance/deer-flow/pull/6934 +[#6935]: https://github.com/bytedance/deer-flow/pull/6935 +[#6939]: https://github.com/bytedance/deer-flow/pull/6939 +[#6945]: https://github.com/bytedance/deer-flow/pull/6945 +[#6946]: https://github.com/bytedance/deer-flow/pull/6946 +[#6948]: https://github.com/bytedance/deer-flow/pull/6948 +[#6950]: https://github.com/bytedance/deer-flow/pull/6950 +[#6951]: https://github.com/bytedance/deer-flow/pull/6951 +[#6952]: https://github.com/bytedance/deer-flow/pull/6952 +[#6953]: https://github.com/bytedance/deer-flow/pull/6953 +[#6957]: https://github.com/bytedance/deer-flow/pull/6957 +[#6959]: https://github.com/bytedance/deer-flow/pull/6959 +[#6961]: https://github.com/bytedance/deer-flow/pull/6961 +[#6967]: https://github.com/bytedance/deer-flow/pull/6967 +[#6969]: https://github.com/bytedance/deer-flow/pull/6969 +[#6971]: https://github.com/bytedance/deer-flow/pull/6971 +[#6973]: https://github.com/bytedance/deer-flow/pull/6973 +[#6975]: https://github.com/bytedance/deer-flow/pull/6975 +[#6977]: https://github.com/bytedance/deer-flow/pull/6977 +[#6980]: https://github.com/bytedance/deer-flow/pull/6980 +[#6981]: https://github.com/bytedance/deer-flow/pull/6981 +[#6984]: https://github.com/bytedance/deer-flow/pull/6984 +[#6990]: https://github.com/bytedance/deer-flow/pull/6990 +[#6992]: https://github.com/bytedance/deer-flow/pull/6992 +[#6995]: https://github.com/bytedance/deer-flow/pull/6995 +[#6998]: https://github.com/bytedance/deer-flow/pull/6998 +[#7001]: https://github.com/bytedance/deer-flow/pull/7001 +[#7002]: https://github.com/bytedance/deer-flow/pull/7002 +[#7004]: https://github.com/bytedance/deer-flow/pull/7004 +[#7014]: https://github.com/bytedance/deer-flow/pull/7014 +[#7017]: https://github.com/bytedance/deer-flow/pull/7017 +[#7018]: https://github.com/bytedance/deer-flow/pull/7018 +[#7020]: https://github.com/bytedance/deer-flow/pull/7020 +[#7023]: https://github.com/bytedance/deer-flow/pull/7023 +[#7024]: https://github.com/bytedance/deer-flow/pull/7024 +[#7031]: https://github.com/bytedance/deer-flow/pull/7031 +[#7033]: https://github.com/bytedance/deer-flow/pull/7033 +[#7035]: https://github.com/bytedance/deer-flow/pull/7035 +[#7039]: https://github.com/bytedance/deer-flow/pull/7039 +[#7042]: https://github.com/bytedance/deer-flow/pull/7042 +[#7051]: https://github.com/bytedance/deer-flow/pull/7051 +[#7053]: https://github.com/bytedance/deer-flow/pull/7053 +[#7057]: https://github.com/bytedance/deer-flow/pull/7057 +[#7058]: https://github.com/bytedance/deer-flow/pull/7058 +[#7059]: https://github.com/bytedance/deer-flow/pull/7059 +[#7061]: https://github.com/bytedance/deer-flow/pull/7061 +[#7065]: https://github.com/bytedance/deer-flow/pull/7065 +[#7074]: https://github.com/bytedance/deer-flow/pull/7074 +[#7075]: https://github.com/bytedance/deer-flow/pull/7075 +[#7076]: https://github.com/bytedance/deer-flow/pull/7076 +[#7078]: https://github.com/bytedance/deer-flow/pull/7078 +[#7084]: https://github.com/bytedance/deer-flow/pull/7084 +[#7093]: https://github.com/bytedance/deer-flow/pull/7093 +[#7106]: https://github.com/bytedance/deer-flow/pull/7106 +[#7108]: https://github.com/bytedance/deer-flow/pull/7108 +[#7112]: https://github.com/bytedance/deer-flow/pull/7112 +[#7116]: https://github.com/bytedance/deer-flow/pull/7116 +[#7117]: https://github.com/bytedance/deer-flow/pull/7117 +[#7122]: https://github.com/bytedance/deer-flow/pull/7122 +[#7127]: https://github.com/bytedance/deer-flow/pull/7127 +[#7140]: https://github.com/bytedance/deer-flow/pull/7140 +[#7141]: https://github.com/bytedance/deer-flow/pull/7141 +[#7144]: https://github.com/bytedance/deer-flow/pull/7144 +[#7148]: https://github.com/bytedance/deer-flow/pull/7148 +[#7150]: https://github.com/bytedance/deer-flow/pull/7150 +[#7151]: https://github.com/bytedance/deer-flow/pull/7151 +[#7152]: https://github.com/bytedance/deer-flow/pull/7152 +[#7154]: https://github.com/bytedance/deer-flow/pull/7154 +[#7163]: https://github.com/bytedance/deer-flow/pull/7163 +[#7167]: https://github.com/bytedance/deer-flow/pull/7167 +[#7170]: https://github.com/bytedance/deer-flow/pull/7170 diff --git a/CHANGELOG_zh.md b/CHANGELOG_zh.md index 02d697cbe4..c108731da1 100644 --- a/CHANGELOG_zh.md +++ b/CHANGELOG_zh.md @@ -10,10 +10,14 @@ ## [未发布] 本节累积面向 **2.2.0** 里程碑([2.2.0](https://github.com/bytedance/deer-flow/milestone/3))的工作。 -该里程碑随本次发布收尾,共合并 **621 个 pull request**。 +截至 2026-10-21,该里程碑已合并 **829 个拉取请求**。 ### 新增 +- **MCP:** 按未变更的服务器缓存完成包装的工具,仅在绑定对账后重新发现缺失或配置 + 发生变化的服务器。将成功但未发现工具的结果与发现失败分开保存,并保留代际、共享 + 重置与 stdio 属主围栏。([#6795]) + - **渠道:** 在 Web UI 中填写的 IM 机器人凭据改存到共享的 `channel_runtime_configs` 表(迁移 `0044_channel_runtime_configs`),不再写入每台主机上明文的 `channels/runtime-config.json`。每个 provider 的配置用 `DEER_FLOW_CREDENTIALS_KEY` @@ -422,6 +426,23 @@ #### 智能体与运行时 +- **上下文:** Gateway 运行请求接受受上限约束的 `context.client` 名称、能力标志与 + 偏好。主智能体通过临时的 user 角色 `` 块接收经过净化的不可信提示, + 用于选择输出格式;这些提示不授予权限,也不写入检查点或运行配置回显。启用 PII + 脱敏时,该块同样会被脱敏。([#7051]) + +- **沙箱:** 为受管的异步 AIO 运行与原生子智能体新增默认关闭的 `sandbox.prewarm`, + 让经授权的沙箱获取与首次模型响应并行。现有执行租约持有并排空尚未完成的获取操作; + 直接使用 SDK 的图及其他提供方仍按需获取。生命周期基准现在会区分真实的资源清理、 + 并发压力与成功测量结果。([#6998]) + +- **验收:** 为委派任务与批次新增 `file: csv-columns:["id","name"]` 条件。 + 通过已授权且有界的读取,按任意顺序精确检查必需表头名称;格式错误的表头判为失败, + 无法获取或不完整的证据保持未验证,不校验数据行。([#6714]) + +- **智能体:** 新增已配置工具组目录,以及自定义智能体的三态工具访问控制。保留已 + 不可用的选项以供移除,只提交实际修改的字段,避免覆盖并发发生的设置变更。([#6630]) + - **目标:** 对话中达成的目标现在会记录在线程上,历史接口的最新一条也会保留目标状态。 评估器判定目标达成时,清除目标的同一个 checkpoint 会写入新的 `goal_outcome` 通道: 目标原文、设置和达成的时间、已用和允许的续跑次数、评估理由、`relied_on_assumption` @@ -637,6 +658,18 @@ #### 知识与检索 +- **知识:** 新增可独立安装的只读 WeKnora 扩展,复用共享的目录、范围、检索和引用 + 流程。显式的端点/租户与 DeerFlow 用户绑定限制访问,经验证的证据及文档/知识库 + 校验保留来源归属。支持 WeKnora v0.8.3,不冒充单个上游用户。([#6950]) + +- **知识:** 通过扩展 API 0.2.7 的提供方注册、能力检查和不可变运行快照,让只读 + 提供方目录与范围选择脱离对 RAGFlow 的依赖。已注册提供方使用稳定的 + `knowledge_search` 接口与共享来源制品。([#6904]) + +- **知识:** 引入与提供方无关的只读检索结果、能力和共享来源证据。LightRAG 与 + RAGFlow 可以使用统一引用,同时继续兼容完整的 RAGFlow 原生快照;来源归属在预算 + 裁剪、委派和重放后仍然保留,调用者伪造的来源键会在 Gateway 边界被剥离。([#6716]) + - **知识库:** 自定义智能体对话可以按消息为 RAGFlow 检索划定范围。 通过可选开启的知识库选择器,可为单轮选择全部运维已批准的数据集、 特定数据集/文件,或本轮不做检索;该选择会以经过校验且不可变的 @@ -689,6 +722,21 @@ #### 模型与集成 +- **决策:** 为现有工具风险门禁、记忆预筛选和信号分类槽位新增可选启用的 OpenAI + Decisions 后端。通过现有 `use:` 路径配置适配器并显式指定模型,保留当前阈值、失败 + 策略、审计和有界传输行为。([#7127]) + +- **向导:** 新增可选的 API Route 网关预设,使用 `https://global.api-route.com/v1`、 + `API_ROUTE_API_KEY` 与现有 ChatOpenAI 集成,默认模型为 `gpt-6.1-sol`。([#6579]) + +- **模型:** 管理员可以通过提供方预设、模型 ID 和 API key 注册受管模型,并可选自定义 + 端点与高级能力。保留凭据加密、配置文件定义的名称及乐观修订检查,变更后刷新对话与 + 智能体的模型选择器。([#6757]) + +- **serper:** 支持用 `SERPER_BASE_URL` 配置兼容的网页与图片搜索端点,在配置的 + 基础地址后追加原有路由,保持 `SERPER_API_KEY`、请求载荷和结果解析不变。未设置 + 或设置为空时仍使用现有端点。([#6483]) + - **社区工具:** 新增 Unbrowse `web_fetch` provider——以 Markdown 形式返回页面 内容:普通 HTTP 足够时直接抓取,需要 JavaScript 的页面则在 Unbrowse 托管的 云端浏览器中渲染(`render: auto|never|always`)。每次抓取仅一次 JSON-RPC @@ -742,6 +790,22 @@ #### 渠道 +- **渠道:** 将显式的主动群通知目标推广到飞书、QQ 和企业微信,并为普通 Web/后台 + 运行的完成、终态失败和等待用户输入新增可选 IM 通知。复用属主偏好、绑定和通知 + 发件箱;运行时事件开关默认关闭,目标完成通知要求裁定为已达成,已回答的澄清会在 + 发送前被丢弃。微信个人通知仍仅面向个人。([#6903]) + +- **渠道:** 为已连接的飞书、企业微信、微信和 QQ 新增共享通知偏好,并支持微信/QQ + 主动私信投递。静音会原子取消待发送/重试中的发件箱记录,重新启用不会释放旧积压。 + 微信要求有效的属主/机器人会话上下文;QQ 投递要求平台返回非空消息 ID 确认。([#6850]) + +- **飞书:** 定时任务可以显式选择一个额外的已绑定群,通过现有发件箱接收通知。 + 省略目标字段时保留原选择,`null` 清除选择;发送时会检查属主和绑定,不会回退到 + 另一个群。([#6762]) + +- **飞书:** 以 Markdown 卡片向已绑定用户投递定时结果与生命周期通知。目标来自 + 经验证的私聊绑定,不会把群或旧版聊天 ID 猜测为私人收件地址。([#6753]) + - **channels:** IM 通道可以在多个 Gateway 实例上运行。`channels.leader_lease` 生效时(默认 `auto` 跟随多进程信号),每个 provider 的平台连接只属于在新表 `channel_leases`(迁移 `0042_channel_leases`)中持有该行的那个实例:归属由一条 @@ -847,6 +911,33 @@ #### 扩展与插件 +- **工作流:** 为兼容的单 Gateway 工作流新增显式、经认证的重启恢复。持久化的桥接 + 日志重放已确认的请求与结果,重新检查会话权限及兼容性;无法确定子运行是否已接纳时 + 要求对账,不会静默再次派发。恢复不会批准尚待人工审核的输出。([#7075]) + +- **技能:** 为可信学习扩展新增带保护的演化宿主 API,包括扩展 API 0.2.7 中有界的 + 已完成运行证据与绑定扩展来源的技能变更能力。经运维显式授权,可以对现有已启用 + 自定义技能的正文/描述进行不可变暂存、校验、比较并交换发布、回退和崩溃恢复。 + 自动发布仅支持 POSIX 单主机本地存储;不包含学习插件或审核 UI。([#5645]) + +- **工作流:** 新增不可变的具名定义、持久化属主审批、进程内人工检查点与带版本的 + 制品字节快照。预览、审批和下游读取使用同一份已审核字节;绑定运行的配置证据记录 + 实际智能体装配结果,不暴露凭据或原始提示词。([#6920]) + +- **工作流:** 新增默认禁用的 Script workflows 扩展,支持串行、分支与有界并行的 + 智能体运行。能力受限的 QuickJS 子进程无法访问环境凭据、文件系统或网络;按属主 + 隔离的记录及启动/查看/取消工具支撑本地化工作流页面,并对不确定的接纳结果要求 + 显式对账。([#6858]) + +- **扩展:** ModelTool 插件可以通过 `PluginToolResult` 选择启用 + `response_format="content_and_artifact"`,将结构化证据与模型可见文本分开保留。 + content/artifact 在统一的 64 KiB UTF-8 JSON 上限内校验并生成快照,同时保留默认 + JSON 返回兼容性与宿主绑定身份。([#6861]) + +- **扩展:** 为 Agent Teams 新增历史分页、已完成结果搜索与有界结果读取,消息轮转或 + 服务重启后仍然可用。按属主限定且绑定查询的游标与截断来源信息,让检索无需再接纳 + 一次智能体运行。([#6793]) + - **插件:** 全栈插件 API 与一个书签示例包。部署安装的 Python 扩展现在可以自带浏览器页面、会话动作与模型工具: `registry.plugin(PluginContribution(...))`(extension-api 0.2.2) @@ -1013,8 +1104,486 @@ 工具栏在键盘聚焦时也会显示。因还有运行未结束而被拒绝的 `/goal` 会保留草稿并说明 原因。([#6556]) +### 变更 + +- **技能:** 将 `allowed-tools` 作为不强制执行的兼容性元数据。激活技能不再隐藏或 + 阻止智能体配置与宿主授权已经允许的工具,即使该声明为空也是如此。保留解析、校验、 + 导出、技能激活权限,以及现有的密钥和用户隔离边界。([#6935]) + ### 修复 +- **社区工具:** 拒绝 LightRAG 与 RAGFlow 的 `knowledge_search` 数值设置中的 + 布尔值,不再静默把 `true` 当作一秒超时、一条结果或一个字符的输出。无效设置返回 + 现有的配置错误。([#7042]) + +- **上传:** 请求取消期间,文件系统操作与资源所有权仍作为整体处理。暂存、转换、 + 发布和远程同步会在完成或回收各自资源后才释放沙箱租约,避免孤立文件与清理竞争。 + ([#7170]) + +- **检查点:** 在运行成功完成后、释放线程的收尾屏障前执行保守保留策略。在检查点 + 写锁下至多删除一个尾部的纯耗时元数据叶节点,保留祖先、兄弟分支与待处理写入。 + ([#6051]) + +- **沙箱:** 在 AIO、BoxLite、E2B、OpenSandbox、Tenki 及共享生命周期中统一用 + 单调时钟测量暖池空闲时长,包括 reset 路径,避免系统时钟校正误删新沙箱或保留 + 已过期沙箱。绝对创建时间仍使用系统时钟。([#7035]) + +- **目标:** 遇到 `loop_capped` 硬停止后不再自动续跑,保留活跃目标以供后续用户轮次 + 继续。目标栏、定时历史与 IM 通知都能识别该停止原因。([#7167]) + +- **渠道:** 在渠道状态、运行时凭据与微信持久化中,把暂存文件关闭、删除及警告日志 + 作为相互独立、尽力执行的清理步骤。清理失败不再替换原始保存错误或跳过剩余清理。 + ([#7106]) + +- **上传:** 保留文档大纲标题中独立的粗体片段,例如 `**Revenue** and **Profit**`, + 不再把它们误认为包裹整个标题的一对标记而留下损坏的 Markdown。([#7150]) + +- **技能:** 在数据分析 Markdown 表格的表头与单元格值中,一致地转义反斜杠、竖线 + 和换行。CSV 与 JSON 导出保持现有行为。([#7163]) + +- **Helm:** 在通用线程路由之前使用专门的 nginx 浏览器流路径,转发 Live Browser + WebSocket 升级,保留 `Upgrade`/`Connection` 请求头与长连接读取超时。([#7148]) + +- **项目:** 即使暂存清理或警告日志也失败,仍保留超大上传的响应、发布错误,以及 + 对已提交书架文档的恢复。([#7141]) + +- **记忆:** 在读取错误分支返回前隔离无法按 UTF-8 读取的记忆摘要,避免后续保存覆盖 + 原始字节的唯一副本。([#7076]) + +- **TUI:** 接受斜杠命令与参数之间的制表符和换行。粘贴的技能任务保留原有缩进与 + 换行,内置命令优先级与保留名称不变。([#7117]) + +- **模型:** 某个凭据来源不可用时继续查找。空白 Claude 环境变量令牌不再遮蔽有效的 + 文件凭据,无效 Codex 令牌字段也不再掩盖另一种有效布局。([#7140]) + +- **记忆:** 抽取繁忙时按到达顺序保留连续的紧急压缩前快照,不再覆盖更早的待处理 + 消息。普通累积更新仍会合并。([#7152]) + +- **Codex:** 在提供方重试中遵循有效的 `retry-after-ms` 和 `Retry-After` 提示。 + 无效、非有限或超过 24 小时的提示回退到现有指数退避;重试状态码与次数限制不变。 + ([#7151]) + +- **前端:** 重连后将仅包含思考的 Anthropic 步骤恢复到其用户消息之后。已完成答案 + 的边界现在由可见内容决定,不再依据非空内容数组。([#7144]) + +- **存储:** 通过现有导入器与子类校验接受单模块 `module:Class` 自定义 blob 后端 + 选择器,与已支持的点号形式一致。([#7017]) + +- **Docker:** 开发环境的 Kubernetes provisioner 改为通过 `provisioner` Compose + profile 按需启用。Docker 包装脚本仅在 provisioner 沙箱模式下启用它,停止时仍会 + 将其移除。([#6948]) + +- **skill-creator:** 独立校验可选 timing 文档及每个令牌/耗时字段。格式错误的测量 + 会发出警告并使用现有回退,不中止基准测试,也不丢弃其他有效测量。([#7078]) + +- **记忆:** 读取标准事实 Markdown 时支持 UTF-8 BOM,避免将有效的手工编辑事实 + 误判为缺少 YAML front matter。([#7116]) + +- **子智能体:** 即使流清理不响应取消,也在配置的执行期限到达时发布 `TIMED_OUT`。 + 清理继续受监督,资源/容量围栏保留到拆除完成,并在有界的尾部窗口内收集晚到的 + 令牌用量。([#7053]) + +- **前端:** 即使 HTTP 状态是 200,也拒绝携带 `success: false` 的上传响应。停止 + 发送对话并保留草稿及附件以供重试,不再缺少被拒文件却仍启动运行。([#7122]) + +- **模型:** 根据当前提供方与端点判断是否复用已保存密钥,撤销连接编辑后不再发送 + 空密钥或删除已有凭据。仍可显式移除密钥。([#6813]) + +- **浏览器:** 即使文件描述符关闭、临时文件删除或诊断日志也失败,仍保留原始截图 + 发布错误或中断。清理步骤继续相互独立、尽力执行。([#6871]) + +- **运行时:** 生产者在持久化终态与完成流之间退出时,恢复 Redis SSE 与 `/wait` + 消费者。令牌围栏保护的生产者租约和第二次空心跳保护晚到的尾部帧。恢复默认关闭, + 由需要重启生效的 `stream_bridge.producer_lease_recovery_enabled` 控制;在所有 + Gateway 启用前,需先排空旧写入者及启用该功能前的运行。([#7093]) + +- **配置:** 接受运维编写的环境变量与密钥文件开头的 UTF-8 BOM,保留有效变量及 + 凭据,不重写文件,也不放宽对格式错误密钥的检查。([#7112]) + +- **受管模型:** 对官方 DeepSeek 端点,将通用的 `minimal` 推理强度映射为 `low`, + 并明确公布其支持的强度选项。第三方端点契约保持现有行为。([#6717]) + +- **流式传输:** Memory 游标恰好是已知最后一个被淘汰的事件时,重放仍保留的后继 + 事件,避免误报重放缺口。无法验证的游标与确实缺失后继事件的情况仍需缺口恢复。 + ([#6812]) + +- **运行时:** 发布完成元数据前要求可归属到本写入者的终态写入确认,对过期属主设置 + 围栏,并按运行隔离租约续期工作。阻塞的 Store I/O 不再饿死其他运行,晚到结果也 + 无法恢复已丢失的所有权。([#6919]) + +- **记忆:** 两种存储实现都接受带 UTF-8 BOM 前缀的 DeerMem 摘要,不再对有效 JSON + 报告损坏或将其隔离。真正格式错误的摘要仍按现有方式处理。([#7084]) + +- **GitHub 研究:** 按 `HEAD` 解析仓库树,由 GitHub 选择实际默认分支,不再从 + `main` 回退到可能过期的 `master`。([#7074]) + +- **前端:** 缓存成功的记忆创建、更新、导入、删除或清空结果前,取消过期查询,避免 + 较早的后台响应在界面上撤销已确认的修改。([#6959]) + +- **MCP:** 将持久任务已移除、禁用或因其他原因无法解析的服务器连接视为永久失败, + 不再针对不存在的连接无限重试轮询与取消。([#7058]) + +- **前端:** 重试失败的自定义智能体设置保存,只有确认保存并回读成功后才报告创建 + 成功。重试耗尽后恢复空闲的“保存”状态,并显示本地化错误反馈。([#6628]) + +- **技能:** 在重名文件与工作表、带引号的路径、SQL 改写和缓存查找中保留数据分析 + 来源身份。有效的 SQL 字面量、CTE 与别名保持原意,不再被来源名称替换误改。([#6739]) + +- **工作区:** 跳过哈希读取时消失的文件并继续生成快照,保留文件变更记录与产出 + 检查。权限及其他 I/O 失败仍作为错误处理。([#7057]) + +- **前端:** 子任务历史中的满页未推进游标时停止分页,丢弃该页并返回已获取的有效 + 前缀,不再反复重试或丢失前面的步骤。([#6729]) + +- **前端:** 编辑消息时,输入法组合输入期间的 Escape 与 Ctrl/Cmd+Enter 交由输入法 + 处理,避免意外取消或提交。([#6768]) + +- **crawl4ai:** 对非对象的 HTTP-200 载荷及非字符串 Markdown 字段返回稳定的响应 + 格式错误,不再暴露原始 Python 属性错误。([#7065]) + +- **技能:** 为激活、自定义技能回读与装配哈希读取 `SKILL.md` 时剥离开头的 UTF-8 + BOM,让模型可见内容和内容指纹与解析器保持一致。([#6984]) + +- **记忆:** 在结果数量限制之前应用 Honcho 类别过滤,不再把未过滤的命中标成请求 + 指定的类别。([#6981]) + +- **智能体:** 将默认及具名智能体的 `SOUL.md` 内容插入系统提示词前,剥离开头的 + UTF-8 BOM。([#7061]) + +- **记忆:** 在逐条归一化边界丢弃置信度超出 `[0, 1]` 的抽取事实,避免一个无效评分 + 导致整个更新失败,并反复抽取同一批消息。([#6971]) + +- **沙箱:** 对字面 `grep` 模式搜索长行,不再沿用正则长行保护而漏报命中。现有的 + 文件、二进制、符号链接、摘要与结果限制仍然适用。([#6969]) + +- **skill-creator:** 即使 grading 已提供耗时,也保留实际记录的令牌数,包括零。 + 仅在令牌测量缺失或为 null 时使用输出字符数回退。([#7033]) + +- **模型:** 推理契约路径容忍非映射的 `when_thinking_enabled.extra_body` 值,避免 + 每次构建模型都因属性错误而崩溃。([#7039]) + +- **制品:** 在捕获的路径与 URL 内保留配对的 ASCII `()`、`[]` 和 `{}` 分隔符, + 同时继续剥离正文中未配对的结束符,让持久句柄解析到原始引用。([#6967]) + +- **searxng:** 将格式错误的 HTTP-200 搜索载荷收敛为格式错误,不再返回原始 Python + 异常或误导性的空结果。有效搜索结果仍然可用。([#6931]) + +- **harness:** 将延迟 MCP schema 提升限定到当前真实用户轮次。新轮次会把此前提升 + 的 schema 重新设为延迟状态,同轮次的发现、执行、并发提升合并与审计保持一致。 + ([#6977]) + +- **智能体:** 工具组实际更新并移除知识访问时,清除继承的 `knowledge_scope`,避免 + 下一次运行因 422 失败。显式 API 范围值仍优先,无关更新保持原状。([#6995]) + +- **运行时:** 为每次运行持久化实际解析出的模型名,包括默认选择和回退,只在已存 + 名称发生变化时写入。运行历史不再保留缺失或仅为请求值的模型名。([#6980]) + +- **tencent-wsa:** 看似数字的配置字符串无法转换为整数时,回退到默认结果数,同时 + 继续接受有效的非 ASCII 十进制数字。([#6973]) + +- **调度器:** 恢复过期启动时,在父任务与执行实例锁下重新检查租约是否有效。即使 + 较早的恢复扫描曾观察到过期,新认领仍保留执行槽位和行状态。([#6975]) + +- **沙箱:** 上报本地 `grep` 采样、打开与读取失败,不再把无法读取的文本报告为 + 无匹配。预期的文件消失仍可跳过,权限及其他 I/O 失败则成为工具错误。([#7004]) + +- **检查点:** 逐条跳过无法序列化的 Redis 历史缓存条目,继续写入其他有效条目。 + 可选缓存不再中断权威历史操作,日志也不包含序列化异常文本。([#7014]) + +- **前端:** 初始运行流在首个持久检查点之前遇到重放缺口时,保留已净化的提交输入, + 通过现有消息 ID 去重将其合入重新加载的状态。([#6800]) + +- **沙箱:** AIO 拆除失败后保留绑定代际的元数据与隔离围栏,确认运行时资源已不存在 + 后才退役记录,并保留失败的关闭目标以供重试,不再误报销毁成功。其他资源仍会被 + 尝试清理。([#7001]) + +- **流式传输:** 在条件锁下退役 Memory 流代际,释放保留的载荷,并以重放缺口信号 + 唤醒尚未读完的消费者。清理不再让订阅者滞留于脱离注册表的缓冲区,也不会让其跟随 + 新创建的代际。([#6992]) + +- **运行时:** 为强制关闭时的 RunJournal 进度快照与事件写入设置有界收尾。不响应 + 取消的持久化仍受监督,不再无限阻塞资源释放或关闭;正常刷新保留持久性语义。 + ([#6990]) + +- **技能:** 不同事件循环上的并发 `skill_manage` 调用现在可以正确唤醒并串行执行, + 避免同步客户端与 TUI 卡住。等待不占用执行器线程,被取消的等待者也不遗留所有权。 + ([#7020]) + +- **流式传输:** 订阅前校验数值重连游标,包括整数转换失败及 Redis 的 ASCII 无符号 + 64 位分量。超大或无效值按格式错误游标策略处理,不再终止订阅。([#6690]) + +- **MCP:** 派发前消费已经解决或缺失的持久任务通知快照,避免跟踪状况恢复后仍启动 + 空通知运行,或持续重试空事件直到进入死信状态。([#6693]) + +- **沙箱:** 写入本地文件或 shell 命令时,转换冒号连接的虚拟路径列表中的每一项, + 保留可用的 PATH、PYTHONPATH 与自定义挂载列表,不再仅转换第一项。([#7002]) + +- **脚本:** 检测可选依赖与允许本地启动时,在显式的 `DEER_FLOW_CONFIG_PATH` + 之后优先使用 `DEER_FLOW_PROJECT_ROOT/config.yaml`。外部项目配置不再丢失必需 + extras,也不因检出目录缺少自身配置而失败。([#6934]) + +- **GitHub 研究:** 对 Contents API 请求中的原始仓库相对文件路径编码一次,在两种 + HTTP 后端中都保留目录分隔符、百分号、查询/片段字符、空格及 Unicode。([#7018]) + +- **上传:** 所有大小的源文件都在线程中转换文档,不再按压缩大小分流,避免体积小但 + 解析昂贵的文件阻塞事件循环。转换仍需显式启用,取消仍等待工作线程完成清理。 + ([#6924]) + +- **沙箱:** 退役已不存在的代际时保留并发写入的隔离围栏。目录刚变为非空不再中断 + 拆除,也不会移除其他 worker 的保护。([#6961]) + +- **TUI:** 桥接期限到达时请求取消尚未完成的持久化工作,避免已放弃的标题更新继续 + 无限制运行。取消仍是协作式的,不会撤销已提交的写入。([#6927]) + +- **infoquest:** 校验搜索响应信封与结果容器,将格式错误的 HTTP-200 载荷报告为 + 格式错误,不再返回 Python 异常或看似成功的空搜索。([#6932]) + +- **MCP:** 改写本地文件结果时原样保留远程 URL 字节,包括带签名的查询字符串与 + 片段。真正的本地路径和 `file:` 引用仍按现有线程根目录检查进行转换。([#6878]) + +- **智能体:** 模型目录正在加载、不可用或未包含实际模型时,保留已保存的思考与推理 + 默认值,避免无关设置编辑静默清除这些覆盖项。([#6907]) + +- **验收:** 识别完整的原生 Node TAP/spec 汇总,要求至少一次实际通过,失败与取消 + 优先。空运行、全部跳过、全部 todo 及不完整记录仍保持未验证,包括带颜色的 Node + 24 输出。([#6953]) + +- **流式传输:** 已观察到的 Redis 流消失时发出重放缺口信号,让 SSE 重新加载持久 + 状态,不再无限发送心跳。`/wait` 在判断运行完成前刷新已持久化的状态。([#6951]) + +- **Docker:** 两种启动器一致处理省略、空白、空引号和 YAML null 的 AIO provisioner + URL,选择本地 AIO 及其 socket overlay,不再错误启动 Kubernetes provisioner。 + ([#6945]) + +- **前端:** 识别抓取内容中一级 Markdown 标题之后的制表符,显示文档标题而不是 + 回退到 URL。保留现有缩进与标题级别限制。([#6923]) + +- **客户端:** 按消息累积流式令牌用量增量,并与完成快照对账,避免重复计数。终态 + 用量和 TUI 现在与 Gemini/vLLM 的纯用量 chunk 及输入令牌修正保持一致。([#6939]) + +- **摘要:** 压缩替换历史前,按从旧到新的顺序分块处理全部选定历史,包括超长消息 + 中连续的片段。只允许缩短生成的摘要承接内容;分块失败、预算无法满足或达到 64 块 + 上限时,原历史保持完整。([#6918]) + +- **harness:** 对 Responses API 的 `incomplete`/`max_output_tokens` 终止应用长度 + 上限策略,包括 SSE。保留文本与推理,抑制已解析和原生工具调用块,防止被截断的 + 调用执行,或在没有工具输出时重放。([#6946]) + +- **验收:** 详细 Go 测试记录中没有通过用例且全部跳过时,保持未验证,不再把 `PASS` + 和包级 `ok` 横幅当作测试实际通过的证据。([#6957]) + +- **压缩:** 原始检查点包含待执行任务或无法检查时,以 HTTP 409 拒绝手动压缩。 + 暂停的工具派发保留其执行位置,不会因新检查点而丢失。([#6929]) + +- **E2B:** 将字面 grep 模式原样传给 `grep -F`,避免额外反斜杠让标点和空格产生 + 假阴性。正则模式仍按现有方式校验。([#6952]) + +- **运行时:** 将宿主取消延后至所有终态收尾阶段完成,包括回执/状态持久化、完成 + 钩子、扩展通知及流 END。所需终态尾部处理结束后,再传播取消。([#6914]) + +- **运行时:** 将 SQLAlchemy 风格的 PostgreSQL DSN 传给同步检查点存储及同步/异步 + Store 前先归一化,即使未配置自定义 schema,也会剥离 `+driver` 后缀。([#6917]) + +- **验收:** 要求完整的 unittest 计数与成功汇总,且至少一个普通测试通过。全部跳过、 + 全部为预期失败的套件和单独的 `OK` 横幅,不再满足 `tests_passed` 条件。([#6916]) + +- **搜索:** 将 DuckDuckGo 依赖、传输及提供方失败上报为错误,不再返回 + `No results found`,让智能体区分服务故障与合法的空查询结果。([#6648]) + +- **社区工具:** 发布前预留 Browserless 截图输出名称,避免并发或同秒截图选中同一个 + 空闲文件名后静默互相覆盖。([#6901]) + +- **子智能体:** 在初始化、执行和验收期间持续续期持久批次租约,并用每次认领的 + 所有权代际约束确认。原子变更阻止过期 SQLite worker 或恢复扫描覆盖较新的尝试。 + ([#6764]) + +- **运行时:** 调用者取消后,已接纳的事件写入仍由 RunJournal 持有。隔离无法确定的 + 提交结果,不重试可能已提交的批次,也不让后续事件超越它,避免事件丢失和重复重放。 + ([#6846]) + +- **serper:** 非空网页或图片结果容器中没有可用对象时,报告响应格式错误,不再声称 + 查询无结果。缺失或确实为空的列表仍视为空。([#6779]) + +- **OpenSandbox:** 对明确的命令期限到达结果报告 `Exit Code: 124`,同时保留部分 + stdout 与 stderr。其他缺失退出码、仅含信号的状态及传输失败保留现有报告方式。 + ([#6885]) + +- **沙箱:** 缩短隔离路径中的哈希分量,避免深层 home 与临时目录触发 Windows + `MAX_PATH` 失败。([#6880]) + +- **上传:** 跳过格式错误的文件名与预期的逐文件探测失败,并安全格式化超大字节数, + 避免无效附件元数据中止轮次或遮蔽同批有效上传。([#6882]) + +- **客户端:** 对账首个状态快照之前追加的文本,只发出超出已流式发送消息的后缀。 + 中间件追加内容现在可以到达嵌入式 `chat()` 调用者,不重复文本、元数据或工具调用。 + ([#6910]) + +- **运行时:** 数据库写入前将传入的运行事件时间戳归一化为 UTC,让 SQLite 丢弃 + 时区偏移后仍表示同一时刻。不重写已有时间戳。([#6894]) + +- **制品:** 为隔离的 HTML 预览提供经过认证的静态资源字节,恢复同目录图片、 + 样式表、CSS 导入与经典脚本,无需授予 iframe 同源访问。([#6701]) + +- **模型:** 在绑定和直接调用中保留 Codex 的 `tool_choice`,HTTP 派发前依据可用 + 函数工具校验强制选择。无工具时仍可使用有效的 `auto` 和 `none`。([#6898]) + +- **模型:** 默认将 `gpt-6` 系列 ChatOpenAI 模型路由到 Responses API,并使用 + `responses/v1` 输出,恢复固定版本适配器的工具调用能力。运维显式设置的 API/输出 + 选项仍优先。([#6863]) + +- **知识:** 将 RAGFlow 原生引用清理限制在其自身命名空间,使混合委派结果中的统一 + `#knowledge-source-...` 链接及证据在工具输出预算处理后仍然保留。([#6886]) + +- **Slack:** 接受用户 `file_share` 事件及纯文件消息,通过现有入站文件流程下载 + 私有附件。其他消息子类型与机器人消息仍被排除。([#6855]) + +- **验收:** 识别执行过测试的完整成功 Cargo 目标汇总,空的同级目标不再否决已通过 + 的目标。单独成功横幅、全部为空或全部忽略的运行仍保持未验证。([#6891]) + +- **serply:** 非空结果容器没有可用对象时视为格式错误,不再报告无搜索结果。 + 缺失或确实为空的容器保持当前行为。([#6796]) + +- **Discord:** 接受纯文件入站消息、提取附件描述,并通过共享摄取流程有界下载 CDN + 字节,保留提及与线程门禁。([#6857]) + +- **MCP:** 会话池承压时仅淘汰空闲属主,按属主身份跟踪普通工具与持久任务的活跃 + 调用。所有会话都忙时拒绝新的获取或提升,不中断已经接纳的调用。([#6900]) + +- **智能体:** 将标准顶层文件/图片 URL 内容块捕获为持久制品句柄,保留旧版 + `source.url` 支持,并从同一种表示中提取 URL 与 MIME 元数据。([#6893]) + +- **前端:** 跨夏令时边界显示已保存的一次性任务时,应用调度器对缺失/重复本地时间 + 的策略。新的缺失时间输入仍无效,仅修改标题时保留已保存时刻。([#6756]) + +- **子智能体:** 测试验收要求完整的 Maven 或 Gradle 运行器计数,且至少一个测试未 + 被跳过。构建成功横幅、跳过的任务与不完整计数不再证明测试通过;已报告失败优先。 + ([#6868]) + +- **记忆:** 在现有获取锁期限内,重试打开作用域锁文件时的 Windows 瞬时失败,避免 + 并发调用首次创建文件时出错。([#6870]) + +- **脚本:** 通过 stdin 而非多行 argv 传入配置升级 Python 程序,避免 Windows shim + 重新解析失败。解析器探测会在 AppConfig 之前显式加载所选环境文件。([#6845]) + +- **tencent-wsa:** 非空 `Pages` 中没有可用页面对象时报告格式错误,保留格式错误 + 响应与合法空搜索之间的区别。([#6799]) + +- **沙箱:** 为 E2B 与 BoxLite 的 bash 期限错误追加 `Exit Code: 124`,向模型与 + 验收检查器提供与其他提供方一致的显式超时标记。([#6848]) + +- **Telegram:** 运行期间缓存的回复目标被删除后,允许继续在私聊发送新回复与附件。 + 工作确认和流式预览采用同一策略;群回复仍保持严格检查以保留论坛路由。([#6791]) + +- **图片查看:** 每次模型请求重新注入的上下文上限为 4 张图片和 28 MiB base64 数据, + 优先纳入近期图片并跳过超预算读取。轻量元数据和省略提示让智能体可以重新查看较早 + 图片,无需再次发送线程的全部图片历史。([#6828], [#6829]) + +- **沙箱:** 将新创建的 E2B 沙箱提供给工具前,恢复已持久化的属主/线程 workspace、 + uploads、outputs 与 ACP 文件。活跃及暖池客户端保留实时内容;恢复失败或超预算 + 时获取失败,并清理尚未完成初始化的虚拟机。([#6824]) + +- **MindIE:** XML 历史重放中遇到无法序列化的工具参数时,回退到字符串渲染,避免 + Python set 或循环载荷导致线程中后续每次请求都失败。([#6839]) + +- **前端:** 在 Markdown 面板与独立查看器中,通过当前线程制品端点解析本地及文档 + 相对图片。文件或线程上下文变化时刷新目标,保留外部 URL 与现有净化逻辑。([#6827]) + +- **沙箱:** 将 AIO 格式错误的文件缺失响应报告为可操作的 + `file not found or unreadable` 错误,不再暴露 SDK 校验细节并诱导反复读取不存在的 + 文件。([#6834]) + +- **模型:** 旧版关闭思考模板容忍显式 null 键,避免原本可接受的 YAML 配置在模型 + 构建时产生属性错误。([#6838]) + +- **上传:** 即使 NTFS 的硬链接计数过期,也允许 Windows 替换上传,并通过 inode + 身份识别已发布的暂存别名。首次认领上传与 POSIX 多链接检查仍保留严格保护。 + ([#6821]) + +- **认证:** 追加登录参数时保留 OIDC 授权端点已有的编码值、空值和重复查询参数, + 同时覆盖发现端点与显式配置覆盖。([#6831]) + +- **Buzz:** 将标量 `allowed_users` 公钥解析为一个成员,通过共享允许列表辅助函数 + 校验条目,不再逐字符迭代或因格式错误标量崩溃。空配置仍拒绝所有用户。([#6811]) + +- **技能:** 要求 front matter 的 `---` 分隔符占据完整一行,仅允许末尾空格/制表符。 + 保留结束分隔符之后指令正文的空行与缩进。([#6817]) + +- **沙箱:** 向非本地命令执行转发 `sandbox.bash_command_timeout`,不再静默使用 + 远程提供方的默认值。([#6782]) + +- **沙箱:** 用单调时钟测量同步 AIO 就绪期限,防止系统时钟校正延长等待,或在沙箱 + 就绪前过早结束等待。([#6823]) + +- **Telegram:** 通过共享清理属主排空被中断的启动工作,仅停止正在运行的 SDK 组件, + 并在轮询循环退出前关闭部分初始化的 Bot HTTP 客户端。取消与超时后仍可重试清理。 + ([#6810]) + +- **微信:** 二维码状态请求改用专门的 30 秒超时,不再使用通用的 10 秒超时,并保留 + 调用者显式覆盖。([#6783]) + +- **扩展:** Agent Teams 结果游标锚点通过哈希生成,不再依赖任务 ID 格式;将已取消 + 请求投影为不可用答案,不作为可搜索的成功结果。取消通知仍保留在历史中。([#6832]) + +- **智能体:** 用单调时钟测量 LLM 熔断器恢复窗口,避免系统时钟变化延长或过早结束 + 快速失败期。绝对 HTTP 日期的重试计算仍使用系统时钟。([#6806]) + +- **循环检测:** 警告级别的智能体可在最终回答前使用文件写入工具保存已收集结果。 + 警告针对重复调用,不再禁止所有工具;阈值与硬停止保持不变。([#6804]) + +- **LLM:** 对未产生任何 generation chunk 的流式 HTTP-200 响应,通过现有瞬时错误 + 退避与预算重试,与非流式空生成情况一致。其他 `ValueError` 仍归为通用错误。 + ([#6803]) + +- **Slack:** 关闭期间继续持有执行器中的连接工作,等待其结束后才在事件循环之外 + 关闭 Socket Mode 客户端。超时或取消的 stop 保留清理所有权以供重试,不再允许 + 晚到的连接重新打开 socket。([#6808]) + +- **制品:** 在应用会话期间,按账号、对话和路径保留未保存的制品草稿。切换到其他 + 线程或工作区页面再返回,不再静默丢弃编辑内容。([#6700]) + +- **Buzz:** `mention_free_channels` 接受单个 ID 或列表,避免标量字符串被拆成字符, + 或数字标量导致连接器初始化崩溃。空白值仍不授予豁免。([#6776]) + +- **浏览器:** 通过临时文件和原子发布写入截图及 Browserless 截图/抓取输出,避免 + 写入失败后在最终制品名称下留下残缺截图。([#6731]) + +- **运行时:** 按规范任务顺序重建缓存的增量历史通道写入,同时保留每个任务内部的 + 写入序列。并行分支步骤之后,Memory 检查点历史不再因缓存冷热而变化。([#6774]) + +- **Telegram:** 有界停止与调用者取消期间保留单个轮询循环清理操作。重试停止会 + 等待同一属主,不再取消清理、提前关闭循环或与另一轮拆除竞争。([#6772]) + +- **前端:** 在输入框中插入引用后立即将光标放到其后,避免即时输入出现在引用之前, + 或晚到的动画帧回调覆盖用户移动的光标位置。([#6762]) + +- **扩展:** 按团队隔离 Agent Teams 执行/控制锁和后台 worker,慢宿主调用不占用 + 调度锁。按属主轮转接纳尝试,派发前预留槽位,使无关团队保持响应,新工作获得 + 公平访问。([#6754]) + +- **记忆:** 子串回退搜索读取完整事实范围,不再仅搜索默认第一页的 100 条;禁用 + 索引检索时,后续页面中的匹配事实也可被发现。([#6732]) + +- **记忆:** 保留自由定义的事实类别,不再把非核心标签改写为 `other`,恢复对 + `personal` 及抽取出的 `knowledge` 等标签的精确类别搜索与回读。([#6733]) + +- **OpenSandbox:** 暖池停放前,将线程中的常规输出文件镜像到属主的本地制品目录, + 使已呈现的报告可通过 Gateway 下载,不再对仅存于远程的文件返回 404。([#6699]) + +- **沙箱:** 对 PowerShell 下原生子进程输出使用宿主区域设置编码回退,在 Windows + 代码页上保留非 ASCII 工具结果,同时保持有效 UTF-8 输出不变。([#6727]) + +- **sofya:** 非空结果列表没有可用对象时报告格式错误,不再把格式错误的搜索/抓取 + 响应视为无结果。([#6719]) + +- **钉钉:** Markdown 回退表格只在未转义的竖线处分列,每侧至多移除一个外边框 + 单元格。转义分隔符与边缘空单元格不再使值偏移到错误标签之下。([#6741]) + +- **前端:** 切换到 Custom cron 时保留当前预设周期,包括星期与月内日期;后续修改 + 预设后也反映新设置,不再恢复过期的自定义表达式。([#6749]) + +- **智能体:** 保留旧文件用于回退时,仍允许更新 SQL 存储中的自定义智能体。仅对 + 文件存储应用旧布局保护,保持 HTTP 与工具更新一致。([#6747]) + - **记忆:** 线程的下一轮落到另一个 Gateway 实例上或进程重启后,DeerMem 不再把已经 抽取过的对话轮次再次交给记忆 LLM。抽取水位(每个线程已抽取到的最后一条消息)此前只 存在进程内缓存中;现在还会写入共享 `storage_path` 下的 @@ -1062,6 +1631,13 @@ 的 id 会留下一个回收站对账永远不会清理的空 `{project_id}/documents/` 目录,而超过单个 路径分量长度的 id 会因 `ENAMETOOLONG` 失败。现在会先确认项目归调用者所有且处于活跃 状态,不写任何内容即返回同样的 `404`;书架插入仍会在项目行锁下再次检查。 ([#7040]) +- **工作流:** 脚本工作流等待耗时较长的子 Agent 运行时,不再无视 `timeout_seconds`, + 在约 209 秒后因 `Worker turn limit` 失败。此前只要步骤尚未完成,监督器就会在每次 + 20 ms 轮询时向 QuickJS worker 重发一个空帧,每次往返都会计入 10,000 次交互上限。 + 现在 worker 会报告其作业队列何时已排空,随后监督器在本地等待尚未完成的调用,不再 + 交换帧(仍每隔 20 ms 检查取消、故障和 worker 退出),因此空闲等待不再消耗交互次数, + `timeout_seconds` 成为唯一的实际耗时上限;持续驱动作业队列的脚本仍受交互次数上限 + 约束。(issue #7022, [#7024]) - **浏览器:** `browser_screenshot` 不再替换线程 outputs 目录中已存在的文件。此前以 `report.png` 保存的截图会覆盖用户自己的 `report.png`、更早的截图,或同一秒内生成的 另一张默认命名截图;现在会像 `web_capture` 一样改用下一个空闲名称(`report-1.png`、 @@ -1092,6 +1668,32 @@ 以便重试。即发即弃渠道(GitHub)不受影响:`runs.create` 在运行进入 pending 后即返回。 ([#6876]) +- **部署:** Gateway 容器现在可以优雅关闭。生产 compose 的 `command`、 + `backend/Dockerfile` 中的两个 `CMD` 以及 Helm chart 此前都通过 + `sh -c "cd backend && … uv run … uvicorn …"` 启动服务,导致没有 SIGTERM 处理器的 + `sh` 成为 PID 1,内核因而丢弃停止信号:uvicorn 从不关闭,lifespan 收尾流程 + (记忆队列刷新、运行排空、渠道、调度器和 MCP 关闭)也从不执行,每次停止都会耗尽 + 宽限期,最终以 SIGKILL(退出码 137)结束。现在所有生产启动路径都像已有的 + `docker/dev-entrypoint.sh` 一样通过 `exec` 执行服务器,compose 的 gateway 也设置了 + `init: true`,确保孤立的孙进程仍能被回收。(issue #6835, [#6836]) + +- **渠道:** `FeishuChannel.stop()` 和 `DingTalkChannel.stop()` 现在会结束各自的 + SDK 线程,不再超时。两个 SDK 都在仅于致命错误时才会退出的线程私有事件循环上运行, + 因此此前每次停止都会等待线程 5 秒、抛出 `ChannelStopTimeout`,并让旧进程的平台连接 + 继续存活;重启、重新部署以及即将引入的按 provider 划分的 leader 交接都无法释放连接。 + 现在各渠道在锁保护下公开该循环,`stop()` 在其上安排关闭操作,再等待线程结束。 + 飞书在关闭 socket 和停止循环前禁用 lark-oapi 的 `_auto_reconnect`,因为 SDK 的 + `start()` 否则会在重连分支中吞掉循环被中断的异常并再次连接;钉钉自行驱动一份 + dingtalk-stream 连接循环(SDK 的循环是 `while True`,还会捕获 `CancelledError`), + 每次连接前重新检查运行标志,并自行通过带超时限制的 `httpx` 发送 ticket 请求 + (SDK 的 `requests.post` 没有超时,端点卡住就可能阻塞线程或进程退出),日志也只 + 记录端点,不再记录携带 ticket 的连接载荷。对端一直不回应关闭帧时,两个渠道都会 + 主动中止传输,而不再把 socket 留给垃圾回收,因为有界的关闭等待会取消 websockets + 自身的关闭超时中止逻辑。共享的 `shutdown_private_loop` 会取消 SDK 遗留的任务、 + 在限定时间内排空并关闭循环;客户端创建前收到停止请求时不会发起连接。 + `ChannelStopTimeout` 现在仅用于线程确实卡在 SDK 调用中的情形。Telegram 原本就 + 以这种方式停止循环,行为不变。([#6798]) + - **前端:** 用户管理设置页不再在静态网站演示中发出注定失败的查询,非管理员的 `?settings=users` 深链接也不再打开仅管理员可见的面板。该页面此前只以 `system_role === "admin"` 判断,而演示用户名义上是管理员,静态响应层又没有 @@ -1341,18 +1943,6 @@ 多出的这次让出在 3.12 上是无操作;已交给属主循环的事件在所有受支持的 Python 版本上都会提交。([#6565]) -- **渠道:** IM 会话在多个 Gateway 副本之间现在会保留同一条 DeerFlow 线程。`ChannelManager` 此前把聊天到线程的绑定 - (`channel_name:chat_id[:topic_id]` → `thread_id`)保存在进程私有的 JSON 文件 `channels/store.json` 中,启动时读取一次、 - 每次变更整体重写,因此在多个 Gateway 实例下,一个实例上创建的绑定对其他实例不可见——同一聊天的下一条消息若落到 - 另一个实例,就会新开第二条线程——并发写入还会互相覆盖文件。现在只要 `database.backend` 是 `sqlite` 或 `postgres`, - 绑定就保存在共享的 `channel_thread_bindings` 表中(迁移 `0038_channel_thread_bindings`);`memory` 后端继续使用 JSON - 文件。升级后的首次启动会把已有的 `store.json` 一次性导入空表(`INSERT … ON CONFLICT DO NOTHING`,因此两个副本同时 - 导入也不会产生重复绑定),并将文件重命名为 `store.json.migrated`;表非空时保持该文件不动;键组成部分超出表列宽度 - 的条目会被跳过并计数,不会让整个导入失败。存储 API 为异步,数据库永远不会阻塞 Gateway 事件循环;飞书的同步 lark - 回调以短暂的有限等待把查询桥接到该循环,数据库未及时应答的查询会在 Gateway 循环上重试(至多 30 秒,之后丢弃消息 - 并记录警告),而不是因缺少映射被路由到新线程;这类延迟消息会占用有限入站队列(`channels.inbound_queue_maxsize`) - 的一个槽位,因此数据库中断不会让积压增长,无法入队的消息会被丢弃并记录警告。([#6558]) - - **子智能体:** 持久子智能体批次的停机清理现在能在调用方被取消之后继续存活。 #6517 加入的批次停止在取消 poller 与条目任务后直接 await 它们,而 Gateway 有界的 `asyncio.wait_for()` 会在停机期限到达时取消 `stop()` 调用方——该取消 @@ -1408,16 +1998,6 @@ 重试交由每次尝试都会被准入的中间件处理,配置与调用方的重试设置都无法重新 启用它;未启用准入的模型与无关的自定义限流器保持既有重试策略。([#6545]) -- **部署:** Helm chart 不再把沙箱 provisioner 钉在单个 Pod 上。`provisioner.replicas`(默认 1,不变)设置副本数, - provisioner Deployment 采用与 gateway 相同的先扩后缩滚动策略(`maxSurge: 1`、`maxUnavailable: 0`),并在 - `provisioner.replicas > 1` 时渲染 `PodDisruptionBudget`(`provisioner.podDisruptionBudget`,`minAvailable: 1`),因此 - 多副本 gateway 部署不会再因为唯一的 provisioner Pod 重启或节点被抽干而丢失沙箱创建能力。provisioner 本身无需改动: - 带标签的沙箱 Pod 和 Service 就是它唯一的注册表,每个处理器都从 API server 回读,create 也已能容忍并发创建者产生的 - `409 AlreadyExists`。chart README 与 provisioner README 记录了副本数所依赖的前提,以及单副本时永远不会渲染该预算的 - 事实。两个预算的 `minAvailable` 都经由同一个辅助函数渲染:它会保留 `"50%"` 这类百分比(此前直接做 `int` 强转——既有 - 的 gateway 预算同样如此——会悄悄把它变成 `0`,一个什么都保护不了的预算),并对 `0`、`"0%"` 及其他不支持的值让渲染 - 失败,报错信息中会指出对应的 values 键。([#6543]) - - **存储:** 文件系统 blob 写入成功后,即使为元数据 sidecar 分配失败也保持 成功。blob 存储把 JSON sidecar 视为附属信息,但其临时文件的分配位于尽力而为 异常处理之外,那里的 `OSError` 会在内容已原子发布之后仍报告写入失败;对已 @@ -1435,7 +2015,7 @@ - **llm-text:** 推理标签清理现在在带引号的属性之外定位开定界符,形如 `` 的空标签不再吞掉其后的答案。此前两个清理函数都把第一个 带引号的 `>` 当作开始标签的结尾,把这个标签视为未闭合的推理段,对 - `{\"answer\":\"yes\"}` 这类输入返回空字符串。现在开定界符 + `{"answer":"yes"}` 这类输入返回空字符串。现在开定界符 在单引号与双引号属性之外查找;带此类属性的自闭合标签会保留其后的答案;共享 的前向扫描器保持既有的标签名边界与悬挂块行为。([#6535]) @@ -1526,18 +2106,6 @@ 现在每次派发都基于调用开始时取得的快照进行,监听器计数日志与回调投递都使用该 快照。([#6502]) -- **认证:** 登录锁定现在按客户端 IP 在所有 Gateway 副本间只计一次。`POST /api/v1/auth/login/local` 此前把失败计数 - 存在进程私有的字典里,因此同一个负载均衡器后挂 N 个副本时,攻击者能获得 N × `max_login_attempts` 次尝试机会, - 一个副本上的锁定对其他副本不可见。该计数现在由 `LoginThrottleStore` 管理:新增的 `auth.local.throttle_storage` - 选择器(默认 `auto`)在 `database.backend` 为 `sqlite` 或 `postgres` 时把计数保存在共享的 `login_throttle` 表中 - (迁移 `0035_login_throttle`),没有可共享的数据库时(`memory` 数据库,或已配置但引擎未初始化的数据库)回退到 - 进程内计数并记录警告;`memory` 强制沿用历史上的进程内行为;`db` 强制使用表,配置的数据库引擎不可用时拒绝启动。 - Gateway 在启动时、紧随持久化引擎之后解析一次该存储;独立应用则在第一次限流调用时解析。失败通过一次原子 upsert - 计数,同时保留生效中锁定的开始时间与已提交时长(判定措辞是“锁定开始后 N 秒”,而非“最后一次尝试之后”);锁定 - 期间策略变化时仍以锁定时提交的时长为准;登录成功会清除该 IP 在所有位置的计数;已生效的锁定与空闲计数按有界 - 批次清扫;声明了多实例部署却仍使用 `memory` 的安装会在启动时记录警告。登录端点的状态码和消息不变; - `max_login_attempts` 与 `lockout_seconds` 仍为实时读取。`config_version` 现为 57。([#6501]) - - **网关:** 带键(keyed)resume 的重试现在是幂等的。运行执行让 `command.resume` 优先于 `input`,而幂等复用此前只比较存储的与重试的 `input`,因此两个 `input=null` 的不同恢复决定可能复用同一个运行。现在带键 resume 的准入会在新增 @@ -1561,28 +2129,6 @@ `enable_thinking=true`,且请求构造会改写模型保存的默认值。现在归一化在请求自有的 副本上进行;显式 `enable_thinking` 保持优先,无关字段得以保留。([#6496]) -- **技能:** 通过一个 Gateway 副本做出的技能变更,现在会进入其他所有副本系统提示词中的技能列表。`SkillStorage` 每次 - 调用都会重新扫描磁盘,但提示词层按进程缓存已启用技能列表和渲染好的 `` 段落,而安装、编辑、删除、 - 回滚或启停技能(以及 `POST /api/skills/reload`)只刷新处理该请求的进程,因此在多个 uvicorn worker 或多个共享同一 - home 卷的 Pod 下,其他副本会一直提供旧技能列表,直到各自重启。现在上述每一种变更还会在共享的 - `extensions_config.json` 旁发布 `.extensions_config.json.skills-cache-reset.json`,使用与配置文件相同的原子替换和 - 跨进程锁;每次返回缓存条目前至多每秒一次地比对该标记的签名;只针对某个用户自定义技能的标记只会让该用户的 - 条目失效。`/api/skills/reload` 在标记写入成功时报告 `scope: shared_config`,在无法解析 extensions 配置路径时报告 - `scope: process`,运维者不再需要在每个 Pod 或 worker 上单独调用。MCP 缓存重置的标记现在与它共用同一个 - `deerflow.config.shared_reset_marker` 辅助函数。([#6495]) - -- **记忆:** DeerMem 派生的 SQLite FTS5 检索索引现在可以放在记忆根目录之外,Gateway 实例也能看到其他实例写入的事实。 - 此前每个用户的索引是 `{storage_path}/.retrieval` 处一个 WAL 模式的 SQLite 数据库,多个共享同一 home 卷的 Gateway Pod - 会经网络文件系统打开同一个 WAL 文件,而 SQLite 不支持这种用法;每个 Pod 启动都会在其他 Pod 仍在使用时清空并重新 - 填充共享索引,一个 Pod 的损坏恢复会删掉其他 Pod 仍打开的文件,而同伴写入新事实之后,Pod 仍继续提供自己那份旧 - 副本。新增的 `memory.backend_config.retrieval_index_path` 可把索引目录放到别处(留空保持现有位置;相对路径基于 - `storage_path` 解析),启动重建与损坏恢复只触及该本地索引;搜索现在会对自本进程上次索引以来 `memory.json` 修订号 - 发生变化的作用域重新同步,因此同伴的事实会出现在下一次搜索中,而本实例自己的写入不会触发重建。声明了多实例 - 部署(`deployment.multi_instance: true` / `DEER_FLOW_MULTI_INSTANCE=1`)却仍把索引放在 `storage_path` 内的安装会在 - 启动时记录警告。Helm chart 现在把 Pod 本地的 `emptyDir` 挂载到 `/var/lib/deerflow/memory-index`,将该配置项指向它, - 并删除了 Gateway 每次启动都会丢弃并警告的遗留 `memory.storage_path: memory.json` 一行。`config_version` 现为 56。 - ([#6494]) - - **部署:** `$DEER_FLOW_HOME` 不可写时,`scripts/deploy.sh` 现在会快速失败并给出 可操作的提示。此前开发栈(`make docker-start`)可能以 root 创建 `backend/.deer-flow`,之后 `make up` 在持久化生成的 `BETTER_AUTH_SECRET` 时深入 @@ -1693,27 +2239,6 @@ 而是直接中止。现在该分支也捕获 `OverflowError`,与其他畸形提示一样将其视为不可 用;同一辅助函数中的日期解析回退此前已防护该情况。([#6455]) -- **网关:** Redis 流桥接不可达时,`GET /health/ready` 现在会报告未就绪。桥接的 Redis 客户端是惰性连接的,此前没有任何 - 逻辑去 ping 它,因此 Redis 宕机的 Gateway 照常启动,对 Kubernetes 就绪探针和 Compose healthcheck 都回答 `200 ready`, - 并继续接收流量,而每次运行的首个发布都在失败;在多实例门槛已把 Redis 桥接设为必需之后,这样的副本完全无法对外 - 提供服务。`StreamBridge` 新增 `ping()`;响应体新增 `stream_bridge` 判定(内存桥接为 `not_configured`),不可达时端点 - 翻转为 503;另新增仅报告、不影响状态码的 `provisioner` 判定,来自沙箱 provisioner 自己的 `/health`(设置了 - `sandbox.provisioner_url` 时),由于所有副本共享同一个 provisioner,它永远不会改变状态码。现在只有超出端点时限的 - 探测才会被标记为不可达,公开探测的门闩改为每种探测一把锁。([#6447]) - -- **上传:** Gateway 启动时对孤立的 `.upload-*.part` 暂存文件的清扫现在会跳过 24 小时内的新文件。此前清扫会删除找到的 - 每一个暂存文件,这对单个 Gateway 没问题,但对共享同一 home 卷的多个副本不成立:滚动更新期间启动的副本会删掉另一个 - 副本仍在写入的上传的暂存文件,该上传随后在原子提交时失败。分块写入会刷新暂存文件的 mtime,因此进行中的上传始终 - 比该阈值年轻;崩溃残留则由 24 小时之后的第一次启动回收,与项目文档暂存已在使用的防护一致。已经与已发布上传共享 - inode 的暂存文件(原子链接与删除暂存名之间发生崩溃所致)在下次启动时仍会被无条件回收,以免该目标文件在下次替换时 - 无法通过多链接安全检查。([#6445]) - -- **沙箱:** AIO 沙箱在凭据放置与容器复用上不再信任未经验证的状态。provisioner 能力探测失败不再被解读为“broker 关闭” - (此前会在负缓存 TTL 期间把明文 lark 凭据目录 bind-mount 进无 broker 的 Pod);broker 模式按 Pod 依据 provisioner 的 - 原子观测加以证实;lark 供应配置冲突会携带能力刷新标记,使部署变更在下一次 acquire 时自愈;隐式 shell 结局不明确的 - 容器由持久化的隔离区(`{DEER_FLOW_HOME}/sandbox-quarantine`)在热复用、重新发现与重启之间设防,按既有的所有权与 - 拆除围栏回收,其记录只有在确认容器确实不存在之后才退役。([#6436]) - - **MCP:** 被取代的 stdio 服务器绑定现在在会话池边界处被围栏隔离。此前 stdio 工具包装器可能比创建它的配置纪元活得更久:旧包装器可以在服务器的连接身份 被取代后仍指向该服务器;进行中的创建者可以在绑定变更后才完成初始化并发布 @@ -1823,14 +2348,6 @@ 持有缺口。现在两处游标写入都经由仓库现有的取消安全 `await_drained()` 排干, 过期认证路径复用现有的 `_save_auth_state_drained()` 辅助函数。([#6389]) -- **配置:** 共享同一份 `extensions_config.json` 的每个 Gateway 进程,现在都能看到其他进程做出的 MCP 与技能变更。此前 - 解析结果按进程只缓存一次,只有处理写入的进程会重新加载,因此在多个 uvicorn worker、或共享卷上的多个 Pod 之下, - 其他进程一直沿用启动时的副本:智能体可用的 MCP 服务器,以及更重要的、由文件系统 MCP 服务器推导出的 local-bash - 绝对路径 allowlist,在各副本之间并不一致,直到每个进程重启。`get_extensions_config()` 现在每次读取都会按文件的路径 - 与内容签名重新校验缓存实例,与 `get_app_config()` 对 `config.yaml` 的做法一致,缓存 `AppConfig` 的 `extensions` 快照 - 也随之更新。截断或无效的修订(例如 bind-mounted 文件上非原子覆盖回退进行到一半时)会保留上一个配置并只记录一次 - 日志;启动时遇到损坏的文件仍然会明确报错失败。([#6386]) - - **记忆:** 无效和原始的助手工具调用现在被排除在记忆采集之外。DeerMem 与 mem0 此前只过滤解析后的 `tool_calls`,但函数参数格式错误的真实 OpenAI 响应 会变成一条 `tool_calls` 为空、`invalid_tool_calls` 非空的 `AIMessage`,于是 @@ -1856,17 +2373,6 @@ 和模式,恢复在发布前把该模式应用到临时文件;写入、`chmod` 或发布失败时,当前 目标文件保持原样,临时文件被清理。([#6366]) -- **Helm:** 默认的 Helm 安装现在又能创建沙箱了。chart 启用沙箱 provisioner 并把 `config.sandbox.provisioner_url` 指向 - 它,但没有任何环节渲染 `PROVISIONER_API_KEY`:provisioner Deployment 没有该环境变量,`-app` Secret 没有该 - 键,内嵌配置也没有 `provisioner_api_key`。自 provisioner 开始强制要求该密钥(#4116)以来,只要密钥为空或不匹配,其 - `verify_api_key` 中间件就会对每个 `/api/*` 请求回答 401,因此每一次沙箱创建都会失败。现在 app Secret 会生成一次该 - 密钥,并像其他 app 密钥一样在升级时保留;gateway 与 provisioner Pod 都从这一个 Secret 读取(`provisioner.enabled` 为 - true 时,用户自管的 `existingAppSecret` 必须携带该键);默认 `config` 设置 `sandbox.provisioner_api_key: - $PROVISIONER_API_KEY`,chart README 的配置示例现在也保留了这一行。`provisioner.enabled: false` 时,gateway 使用运维者 - 通过 `secrets` 或 `existingSecret` 提供的密钥(外部 provisioner);否则其启动命令把该变量默认为空字符串,因此即使用户 - 自管的 provider Secret 只包含模型密钥,默认 `config` 也能加载,gateway 照常启动。docker-compose 不受影响:它从 `.env` - 读取该密钥。([#6365]) - - **智能体:** `ReadBeforeWriteMiddleware` 的读取标记现在绑定到执行读取的那个 工具调用。Agent 工具可以返回携带自身结果和对其他消息更新的 LangGraph `Command`,而中间件此前不加区分地取最后一个 `ToolMessage`,于是一次失败或无 @@ -1914,20 +2420,6 @@ 直接释放与沙箱工具中的直接释放回滚,现在都经由既有的取消安全 `await_drained()` 辅助函数排空。([#6348]) -- **部署:** Helm chart 与 docker-compose 不再自带多副本陷阱。chart 的默认 `config` 启用 `run_ownership.heartbeat_enabled` - 和 `run_events.backend: db`(这样启动中的 Pod 只会认领属主确实已消失的运行,消息历史跨 Pod 共享);按 `gateway.replicas` - 或显式的 `gateway.multiInstance` 为 Gateway 的启动门槛导出 `DEER_FLOW_MULTI_INSTANCE`(用 `kubectl scale` 或 HPA 扩容前 - 先设置它,chart 看不到这类扩容);生成并注入共享的 `AUTH_JWT_SECRET`(此前每个 Pod 各自的 `.jwt_secret` 文件会让用户 - 在副本之间被登出;gateway 为多实例时该密钥为必需,避免并发启动的 Pod 竞相写入不同的密钥);声明先扩后缩的滚动 - 策略;为多实例 gateway 渲染 `PodDisruptionBudget`;并在 90 秒终止宽限期内约束 uvicorn 的优雅关闭 - (`gateway.uvicornGracefulShutdownSeconds`,10 秒;`0` 会被遵守),空闲 SSE 流不会再把记忆落盘拖进 SIGKILL。 - `existingAppSecret` 现在被所有消费者遵守(gateway 和 frontend 此前一直引用并未渲染的生成版 `-app` Secret, - 导致 Pod 根本无法启动)。两个 compose 文件也绑定同样的 uvicorn 超时并设置 `stop_grace_period: 90s`(Docker 默认的 - 10 秒会打断 30 秒的记忆落盘;把每个有界拆除钩子都算上,lifespan 的最坏情况约 61 秒,测试会直接从 Gateway 读取这些 - 界限)。chart README 与 compose 注释不再引用早已关闭的 issue #3948 作为保持单副本的理由,改为列出真正仍需单实例的 - 部分(IM 渠道、微信扫码登录、浏览器工具)。升级早于 `AUTH_JWT_SECRET` 的发布版本会生成新密钥,并把所有浏览器会话 - 登出一次;chart README 说明了如何先把旧密钥写入 Secret 以保留会话。([#6347]) - - **MCP:** 轮换式 OAuth refresh token 现在在工具发现与持久 MCP 任务调用之间 共享。这两条路径此前各自解析一份部署配置副本,启用轮换时发现可能把 refresh token R0 换成 R1,而 Gateway 的调用方仍持有 R0,第一次任务提交在到达远端工具 @@ -2049,9 +2541,17 @@ 现在 Jina 请求会跟随重定向,同时保留现有的代理、环境与超时设置,临时重定向 以 POST 方法原样到达目标。([#5808]) -- **目标:** 外部 state 和运行输入在写入前拒绝缺失或无效的目标文本、错误计数及 reducer 控制标记,保持合法的稀疏 - goal 状态兼容。重放历史 checkpoint(包括重新生成回答)沿用当前 goal 和已用续跑 - 预算,不会恢复旧目标,并移除旧回答的达成记录;不需要前端改动或数据库迁移。 +- **渠道:** IM 会话在多个 Gateway 副本之间现在会保留同一条 DeerFlow 线程。`ChannelManager` 此前把聊天到线程的绑定 + (`channel_name:chat_id[:topic_id]` → `thread_id`)保存在进程私有的 JSON 文件 `channels/store.json` 中,启动时读取一次、 + 每次变更整体重写,因此在多个 Gateway 实例下,一个实例上创建的绑定对其他实例不可见——同一聊天的下一条消息若落到 + 另一个实例,就会新开第二条线程——并发写入还会互相覆盖文件。现在只要 `database.backend` 是 `sqlite` 或 `postgres`, + 绑定就保存在共享的 `channel_thread_bindings` 表中(迁移 `0038_channel_thread_bindings`);`memory` 后端继续使用 JSON + 文件。升级后的首次启动会把已有的 `store.json` 一次性导入空表(`INSERT … ON CONFLICT DO NOTHING`,因此两个副本同时 + 导入也不会产生重复绑定),并将文件重命名为 `store.json.migrated`;表非空时保持该文件不动;键组成部分超出表列宽度 + 的条目会被跳过并计数,不会让整个导入失败。存储 API 为异步,数据库永远不会阻塞 Gateway 事件循环;飞书的同步 lark + 回调以短暂的有限等待把查询桥接到该循环,数据库未及时应答的查询会在 Gateway 循环上重试(至多 30 秒,之后丢弃消息 + 并记录警告),而不是因缺少映射被路由到新线程;这类延迟消息会占用有限入站队列(`channels.inbound_queue_maxsize`) + 的一个槽位,因此数据库中断不会让积压增长,无法入队的消息会被丢弃并记录警告。([#6558]) - **运行时:** JSONL 事件存储在末行写坏后不再丢失事件。写入中途被打断会让文件缺少结尾换行,下一次追加会接在残缺记录后面, 两者合成一行无法解析;被截断的多字节字符还会让整个文件解码失败,所有完好记录都读不出来,序号恢复也随之失效。现在追加前 @@ -2073,9 +2573,43 @@ 不会改变任务的状态和 `next_run_at`,与周期任务的试运行一致,其结果只记录在试运行自己的运行记录上。执行时间已过之后 的试运行仍算作任务本身的执行。若试运行的启动记录在轮询器认领已到期的任务之后才写入,也不会再清除该认领的租约;此前这会让 该认领的入队失败,任务停留在 `running` 且没有任何待执行的运行。([#6512]) +- **认证:** 登录锁定现在按客户端 IP 在所有 Gateway 副本间只计一次。`POST /api/v1/auth/login/local` 此前把失败计数 + 存在进程私有的字典里,因此同一个负载均衡器后挂 N 个副本时,攻击者能获得 N × `max_login_attempts` 次尝试机会, + 一个副本上的锁定对其他副本不可见。该计数现在由 `LoginThrottleStore` 管理:新增的 `auth.local.throttle_storage` + 选择器(默认 `auto`)在 `database.backend` 为 `sqlite` 或 `postgres` 时把计数保存在共享的 `login_throttle` 表中 + (迁移 `0035_login_throttle`),没有可共享的数据库时(`memory` 数据库,或已配置但引擎未初始化的数据库)回退到 + 进程内计数并记录警告;`memory` 强制沿用历史上的进程内行为;`db` 强制使用表,配置的数据库引擎不可用时拒绝启动。 + Gateway 在启动时、紧随持久化引擎之后解析一次该存储;独立应用则在第一次限流调用时解析。失败通过一次原子 upsert + 计数,同时保留生效中锁定的开始时间与已提交时长(判定措辞是“锁定开始后 N 秒”,而非“最后一次尝试之后”);锁定 + 期间策略变化时仍以锁定时提交的时长为准;登录成功会清除该 IP 在所有位置的计数;已生效的锁定与空闲计数按有界 + 批次清扫;声明了多实例部署却仍使用 `memory` 的安装会在启动时记录警告。登录端点的状态码和消息不变; + `max_login_attempts` 与 `lockout_seconds` 仍为实时读取。`config_version` 现为 57。([#6501]) + +- **记忆:** DeerMem 派生的 SQLite FTS5 检索索引现在可以放在记忆根目录之外,Gateway 实例也能看到其他实例写入的事实。 + 此前每个用户的索引是 `{storage_path}/.retrieval` 处一个 WAL 模式的 SQLite 数据库,多个共享同一 home 卷的 Gateway Pod + 会经网络文件系统打开同一个 WAL 文件,而 SQLite 不支持这种用法;每个 Pod 启动都会在其他 Pod 仍在使用时清空并重新 + 填充共享索引,一个 Pod 的损坏恢复会删掉其他 Pod 仍打开的文件,而同伴写入新事实之后,Pod 仍继续提供自己那份旧 + 副本。新增的 `memory.backend_config.retrieval_index_path` 可把索引目录放到别处(留空保持现有位置;相对路径基于 + `storage_path` 解析),启动重建与损坏恢复只触及该本地索引;搜索现在会对自本进程上次索引以来 `memory.json` 修订号 + 发生变化的作用域重新同步,因此同伴的事实会出现在下一次搜索中,而本实例自己的写入不会触发重建。声明了多实例 + 部署(`deployment.multi_instance: true` / `DEER_FLOW_MULTI_INSTANCE=1`)却仍把索引放在 `storage_path` 内的安装会在 + 启动时记录警告。Helm chart 现在把 Pod 本地的 `emptyDir` 挂载到 `/var/lib/deerflow/memory-index`,将该配置项指向它, + 并删除了 Gateway 每次启动都会丢弃并警告的遗留 `memory.storage_path: memory.json` 一行。`config_version` 现为 56。 + ([#6494]) + - **技能:** `/技能名` 激活现在在模型调用重试时不再丢失。此前激活在调用模型之前就被标记为已完成,因此调用失败 (限流、过载、超时)或返回空响应而重试时,重试请求不再包含 `SKILL.md` 正文,而该技能的工具限制仍然生效。现在重试 会携带与首次尝试相同的激活内容,不会重新读取技能或重复记录激活,重试得到的响应也保留技能使用记录。([#6506]) +- **技能:** 通过一个 Gateway 副本做出的技能变更,现在会进入其他所有副本系统提示词中的技能列表。`SkillStorage` 每次 + 调用都会重新扫描磁盘,但提示词层按进程缓存已启用技能列表和渲染好的 `` 段落,而安装、编辑、删除、 + 回滚或启停技能(以及 `POST /api/skills/reload`)只刷新处理该请求的进程,因此在多个 uvicorn worker 或多个共享同一 + home 卷的 Pod 下,其他副本会一直提供旧技能列表,直到各自重启。现在上述每一种变更还会在共享的 + `extensions_config.json` 旁发布 `.extensions_config.json.skills-cache-reset.json`,使用与配置文件相同的原子替换和 + 跨进程锁;每次返回缓存条目前至多每秒一次地比对该标记的签名;只针对某个用户自定义技能的标记只会让该用户的 + 条目失效。`/api/skills/reload` 在标记写入成功时报告 `scope: shared_config`,在无法解析 extensions 配置路径时报告 + `scope: process`,运维者不再需要在每个 Pod 或 worker 上单独调用。MCP 缓存重置的标记现在与它共用同一个 + `deerflow.config.shared_reset_marker` 辅助函数。([#6495]) + - **持久化:** `scripts/migrate_user_isolation.py` 现在会把每个 legacy 线程移动到其所属用户下。此前脚本在 `{base_dir}/deer-flow.db` 中查找线程归属,而 DeerFlow 从不创建这个文件(数据库是 `{sqlite_dir}/deerflow.db` 或 PostgreSQL),因此归属映射始终为空,所有 legacy 线程都被移到 `users/default/`。现在归属从 `config.yaml` @@ -2090,6 +2624,21 @@ 与退出码,现在会按返回结果的方式格式化。stderr 中恰好包含 "sandbox not found" 的失败命令 也不再把沙箱标记为已回收。e2b 的 `list_dir` 也会处理同一异常:目录不存在时抛出 `FileNotFoundError`,超过 500 条被截断(SIGPIPE 141)的列表会正常返回,不再以 `OSError` 失败。([#6441]) +- **上传:** Gateway 启动时对孤立的 `.upload-*.part` 暂存文件的清扫现在会跳过 24 小时内的新文件。此前清扫会删除找到的 + 每一个暂存文件,这对单个 Gateway 没问题,但对共享同一 home 卷的多个副本不成立:滚动更新期间启动的副本会删掉另一个 + 副本仍在写入的上传的暂存文件,该上传随后在原子提交时失败。分块写入会刷新暂存文件的 mtime,因此进行中的上传始终 + 比该阈值年轻;崩溃残留则由 24 小时之后的第一次启动回收,与项目文档暂存已在使用的防护一致。已经与已发布上传共享 + inode 的暂存文件(原子链接与删除暂存名之间发生崩溃所致)在下次启动时仍会被无条件回收,以免该目标文件在下次替换时 + 无法通过多链接安全检查。([#6445]) + +- **网关:** Redis 流桥接不可达时,`GET /health/ready` 现在会报告未就绪。桥接的 Redis 客户端是惰性连接的,此前没有任何 + 逻辑去 ping 它,因此 Redis 宕机的 Gateway 照常启动,对 Kubernetes 就绪探针和 Compose healthcheck 都回答 `200 ready`, + 并继续接收流量,而每次运行的首个发布都在失败;在多实例门槛已把 Redis 桥接设为必需之后,这样的副本完全无法对外 + 提供服务。`StreamBridge` 新增 `ping()`;响应体新增 `stream_bridge` 判定(内存桥接为 `not_configured`),不可达时端点 + 翻转为 503;另新增仅报告、不影响状态码的 `provisioner` 判定,来自沙箱 provisioner 自己的 `/health`(设置了 + `sandbox.provisioner_url` 时),由于所有副本共享同一个 provisioner,它永远不会改变状态码。现在只有超出端点时限的 + 探测才会被标记为不可达,公开探测的门闩改为每种探测一把锁。([#6447]) + - **前端:** 附件上传失败后重试发送时,现在会保留原先附带的上下文。输入框此前在发送开始时(附件上传之前)就清除了 引用、对话引用、已暂存的项目文件和已保存的草稿,因此上传失败后文字和文件虽仍在,重试发送却缺少这些上下文。 现在这些一次性状态只在发送真正派发(上传完成)后才清除;若上传完成时用户已切换对话或离开页面,只清除该次发送 @@ -2115,6 +2664,12 @@ 因此在创建侧边对话或上传附件失败时,已输入的文字和附件都会丢失;发往新侧边对话的第一条消息也会在排队时(实际发送前) 就被清空。现在提交处理会在提示后抛出错误,排队的首条发送也以其自身结果完成提交,因此草稿会保留以便重试,只有消息 实际发出后才会清空。([#6407]) +- **沙箱:** AIO 沙箱在凭据放置与容器复用上不再信任未经验证的状态。provisioner 能力探测失败不再被解读为“broker 关闭” + (此前会在负缓存 TTL 期间把明文 lark 凭据目录 bind-mount 进无 broker 的 Pod);broker 模式按 Pod 依据 provisioner 的 + 原子观测加以证实;lark 供应配置冲突会携带能力刷新标记,使部署变更在下一次 acquire 时自愈;隐式 shell 结局不明确的 + 容器由持久化的隔离区(`{DEER_FLOW_HOME}/sandbox-quarantine`)在热复用、重新发现与重启之间设防,按既有的所有权与 + 拆除围栏回收,其记录只有在确认容器确实不存在之后才退役。([#6436]) + - **前端:** 刷新页面后的首次重连失败时,现在会在同一标签页中重试。SDK 只根据标签页的 `lg:stream` 指针重连一次,出错时保留该指针;而活动运行恢复会跳过指针匹配的运行, 因此实时流在再次刷新前一直无法恢复。现在该重连失败时(包括流中途断开),恢复逻辑会释放指针; @@ -2140,6 +2695,14 @@ 因此会压缩响应的代理(例如不经 nginx、直接 `pnpm start` 时的 Next.js 改写代理) 不再先缓冲整段流、再成批送出。`X-Accel-Buffering: no` 与 `Content-Location` 保持不变,使用 nginx 的部署不受影响。([#6393]) +- **配置:** 共享同一份 `extensions_config.json` 的每个 Gateway 进程,现在都能看到其他进程做出的 MCP 与技能变更。此前 + 解析结果按进程只缓存一次,只有处理写入的进程会重新加载,因此在多个 uvicorn worker、或共享卷上的多个 Pod 之下, + 其他进程一直沿用启动时的副本:智能体可用的 MCP 服务器,以及更重要的、由文件系统 MCP 服务器推导出的 local-bash + 绝对路径 allowlist,在各副本之间并不一致,直到每个进程重启。`get_extensions_config()` 现在每次读取都会按文件的路径 + 与内容签名重新校验缓存实例,与 `get_app_config()` 对 `config.yaml` 的做法一致,缓存 `AppConfig` 的 `extensions` 快照 + 也随之更新。截断或无效的修订(例如 bind-mounted 文件上非原子覆盖回退进行到一半时)会保留上一个配置并只记录一次 + 日志;启动时遇到损坏的文件仍然会明确报错失败。([#6386]) + - **中间件:** 工具输出预算不再让子智能体证据丢失失败的 shell 退出码。长度介于 `externalize_min_chars`(12,000)与沙箱上限(20,000)之间的 bash 结果会被替换为 以 `Access:` 页脚结尾的预览,结尾的 `Exit Code: N` 不再位于最后, @@ -2159,6 +2722,17 @@ 而下一条提示已在同一线程上运行;最后写入检查点的运行会成为会话历史,新的一轮可能因此悄然消失。 现在在被中断的工作线程返回之前,在该会话中发送提示会显示提示信息而不会启动第二个运行; 其他会话仍可通过 `/new` 和 `/resume` 使用。([#6350]) +- **Helm:** 默认的 Helm 安装现在又能创建沙箱了。chart 启用沙箱 provisioner 并把 `config.sandbox.provisioner_url` 指向 + 它,但没有任何环节渲染 `PROVISIONER_API_KEY`:provisioner Deployment 没有该环境变量,`-app` Secret 没有该 + 键,内嵌配置也没有 `provisioner_api_key`。自 provisioner 开始强制要求该密钥(#4116)以来,只要密钥为空或不匹配,其 + `verify_api_key` 中间件就会对每个 `/api/*` 请求回答 401,因此每一次沙箱创建都会失败。现在 app Secret 会生成一次该 + 密钥,并像其他 app 密钥一样在升级时保留;gateway 与 provisioner Pod 都从这一个 Secret 读取(`provisioner.enabled` 为 + true 时,用户自管的 `existingAppSecret` 必须携带该键);默认 `config` 设置 `sandbox.provisioner_api_key: + $PROVISIONER_API_KEY`,chart README 的配置示例现在也保留了这一行。`provisioner.enabled: false` 时,gateway 使用运维者 + 通过 `secrets` 或 `existingSecret` 提供的密钥(外部 provisioner);否则其启动命令把该变量默认为空字符串,因此即使用户 + 自管的 provider Secret 只包含模型密钥,默认 `config` 也能加载,gateway 照常启动。docker-compose 不受影响:它从 `.env` + 读取该密钥。([#6365]) + - **沙箱:** 启用 host bash 时,本地沙箱不再把线程固定在上一个受限 Agent 的技能视图上。 该视图只在 host bash 关闭时维护,但 `LocalSandboxProvider` 只要它存在就会挂载,导致该线程之后 不受限的运行仍沿用旧的 allowlist,读不到 `/mnt/skills` 下其他已启用或新增的技能。现在这些运行 @@ -2195,6 +2769,30 @@ 验收条件。现在警告插在结尾的 `Exit Code: N` 或 `Command exited with code N` 之前,整段只有 `Command exited with code N` 的输出保持原样,结果保留 `deerflow_tool_meta`、`artifact` 与 `id`。([#6307]) +- **部署:** Helm chart 与 docker-compose 不再自带多副本陷阱。chart 的默认 `config` 启用 `run_ownership.heartbeat_enabled` + 和 `run_events.backend: db`(这样启动中的 Pod 只会认领属主确实已消失的运行,消息历史跨 Pod 共享);按 `gateway.replicas` + 或显式的 `gateway.multiInstance` 为 Gateway 的启动门槛导出 `DEER_FLOW_MULTI_INSTANCE`(用 `kubectl scale` 或 HPA 扩容前 + 先设置它,chart 看不到这类扩容);生成并注入共享的 `AUTH_JWT_SECRET`(此前每个 Pod 各自的 `.jwt_secret` 文件会让用户 + 在副本之间被登出;gateway 为多实例时该密钥为必需,避免并发启动的 Pod 竞相写入不同的密钥);声明先扩后缩的滚动 + 策略;为多实例 gateway 渲染 `PodDisruptionBudget`;并在 90 秒终止宽限期内约束 uvicorn 的优雅关闭 + (`gateway.uvicornGracefulShutdownSeconds`,10 秒;`0` 会被遵守),空闲 SSE 流不会再把记忆落盘拖进 SIGKILL。 + `existingAppSecret` 现在被所有消费者遵守(gateway 和 frontend 此前一直引用并未渲染的生成版 `-app` Secret, + 导致 Pod 根本无法启动)。两个 compose 文件也绑定同样的 uvicorn 超时并设置 `stop_grace_period: 90s`(Docker 默认的 + 10 秒会打断 30 秒的记忆落盘;把每个有界拆除钩子都算上,lifespan 的最坏情况约 61 秒,测试会直接从 Gateway 读取这些 + 界限)。chart README 与 compose 注释不再引用早已关闭的 issue #3948 作为保持单副本的理由,改为列出真正仍需单实例的 + 部分(IM 渠道、微信扫码登录、浏览器工具)。升级早于 `AUTH_JWT_SECRET` 的发布版本会生成新密钥,并把所有浏览器会话 + 登出一次;chart README 说明了如何先把旧密钥写入 Secret 以保留会话。([#6347]) + +- **部署:** Helm chart 不再把沙箱 provisioner 钉在单个 Pod 上。`provisioner.replicas`(默认 1,不变)设置副本数, + provisioner Deployment 采用与 gateway 相同的先扩后缩滚动策略(`maxSurge: 1`、`maxUnavailable: 0`),并在 + `provisioner.replicas > 1` 时渲染 `PodDisruptionBudget`(`provisioner.podDisruptionBudget`,`minAvailable: 1`),因此 + 多副本 gateway 部署不会再因为唯一的 provisioner Pod 重启或节点被抽干而丢失沙箱创建能力。provisioner 本身无需改动: + 带标签的沙箱 Pod 和 Service 就是它唯一的注册表,每个处理器都从 API server 回读,create 也已能容忍并发创建者产生的 + `409 AlreadyExists`。chart README 与 provisioner README 记录了副本数所依赖的前提,以及单副本时永远不会渲染该预算的 + 事实。两个预算的 `minAvailable` 都经由同一个辅助函数渲染:它会保留 `"50%"` 这类百分比(此前直接做 `int` 强转——既有 + 的 gateway 预算同样如此——会悄悄把它变成 `0`,一个什么都保护不了的预算),并对 `0`、`"0%"` 及其他不支持的值让渲染 + 失败,报错信息中会指出对应的 values 键。([#6543]) + - **持久化:** 另一个实例正在执行 PostgreSQL 模式迁移时,第二个 Gateway 实例不再 因 `TimeoutError` 启动失败。引导期 advisory lock 此前在应用引擎上以阻塞的 `pg_advisory_lock` 获取,而该引擎的 asyncpg `database.command_timeout`(默认 @@ -2467,23 +3065,6 @@ `custom/` 下的一级链接,但 `delete_custom_skill` 用 `shutil.rmtree` 删除包目录,而它拒绝 符号链接:删除在写入历史记录之后以 `OSError` 失败,退出时清空了用户的技能投影视图, `DELETE /api/skills/custom/{name}` 返回 500。现在只移除链接本身,绝不触碰其指向的外部目录。([#5881]) -- **开发:** 当同级 worktree 的路径包含空格时,`make stop` / `make dev` 现在也能回收它占用的 - 开发端口。`serve.sh` 用 `awk '{print $2}'` 解析 `git worktree list --porcelain` 来构建 - worktree 根目录列表,而该输出中的路径不加引号,因此 `.../deer flow two` 被记录成了 - `.../deer`;从那个 worktree 启动的 Gateway 或前端永远不会被识别为 deer-flow 的进程, - 启动会以“端口已被占用”中止。现在会保留整条路径。([#5856]) -- **上传:** 运行消息元数据中格式错误的 `files[*].size` 不再导致整个运行失败。 - `UploadsMiddleware` 对客户端提供的文件条目的其他字段都做了容错校验,唯独把 `size` 直接交给 - `int()`,因此 `"abc"` 或列表这样的值会在调用模型之前从 `before_agent` 抛出——而且由于该条目 - 会被原样带入,之后每次编辑或重新生成这条消息都会再次失败。该字段只用于 `` - 里的可读大小;现在无法使用的值会回退为 `0`,与缺失时一致,数字字符串仍然有效。([#5855]) -- **发布:** 版本升级不再把 `backend/uv.lock` 落下。`scripts/bump_version.sh` 会改写 - `backend/pyproject.toml`、`frontend/package.json` 与 Helm chart,但 lockfile 同样记录了 - 根包自身的版本(uv 保留其 PEP 440 形式,因此 `2.1.0-rc0` 存为 `2.1.0rc0`),于是文档给出的 - 发布步骤产出的提交会被 lock 相关 CI 拦下:`uv lock --check` 判其过期,`uv sync --locked` - 也会拒绝该工作区;装了 pre-commit 时还会更早在 `uv-lock-check` 钩子上失败。现在该脚本会用 - `uv lock` 刷新 lockfile,并在缺少 `uv` 时于修改任何文件之前退出,而不是留下一个只改一半的 - 工作区。实际改动仅涉及根包的那一行版本号。([#5859]) - **前端:** 子任务渲染状态不再在 `MessageList` 渲染过程中被就地修 改。子任务同步从渲染阶段移入 effect,因此即使任务上下文尚未发布 更新,卡片也能立即拿到纯派生自消息的快照——修复了最终流式参数与 @@ -3355,6 +3936,23 @@ 器现在通过共享的 `file_signature.read_config_with_signature()` helper 只读取一次,并对返回的字节精确签名;竞态编辑最多 只多付出一次重载。([#5848]) +- **开发:** 当同级 worktree 的路径包含空格时,`make stop` / `make dev` 现在也能回收它占用的 + 开发端口。`serve.sh` 用 `awk '{print $2}'` 解析 `git worktree list --porcelain` 来构建 + worktree 根目录列表,而该输出中的路径不加引号,因此 `.../deer flow two` 被记录成了 + `.../deer`;从那个 worktree 启动的 Gateway 或前端永远不会被识别为 deer-flow 的进程, + 启动会以“端口已被占用”中止。现在会保留整条路径。([#5856]) +- **上传:** 运行消息元数据中格式错误的 `files[*].size` 不再导致整个运行失败。 + `UploadsMiddleware` 对客户端提供的文件条目的其他字段都做了容错校验,唯独把 `size` 直接交给 + `int()`,因此 `"abc"` 或列表这样的值会在调用模型之前从 `before_agent` 抛出——而且由于该条目 + 会被原样带入,之后每次编辑或重新生成这条消息都会再次失败。该字段只用于 `` + 里的可读大小;现在无法使用的值会回退为 `0`,与缺失时一致,数字字符串仍然有效。([#5855]) +- **发布:** 版本升级不再把 `backend/uv.lock` 落下。`scripts/bump_version.sh` 会改写 + `backend/pyproject.toml`、`frontend/package.json` 与 Helm chart,但 lockfile 同样记录了 + 根包自身的版本(uv 保留其 PEP 440 形式,因此 `2.1.0-rc0` 存为 `2.1.0rc0`),于是文档给出的 + 发布步骤产出的提交会被 lock 相关 CI 拦下:`uv lock --check` 判其过期,`uv sync --locked` + 也会拒绝该工作区;装了 pre-commit 时还会更早在 `uv-lock-check` 钩子上失败。现在该脚本会用 + `uv lock` 刷新 lockfile,并在缺少 `uv` 时于修改任何文件之前退出,而不是留下一个只改一半的 + 工作区。实际改动仅涉及根包的那一行版本号。([#5859]) - **沙箱:** `glob` 与 `grep` 不再在搜索根目录(或其任一祖先目录)命中忽略模式(如 `build`、 `dist`、`logs`、`node_modules`、`coverage`、`target`)时返回空结果。此前各远端沙箱把 `should_ignore_path` 用在**绝对路径**上,而该函数会检查路径的每一段,于是树上任意位置的忽略名 @@ -4606,6 +5204,20 @@ 因为它会把相对路径的 `cd` 移出工作区。`$PWD/...` 仍然允许,因为它与对应的相对路径 指向同一文件,除非命令自己重新绑定了 `PWD`。URL 中的变量不受影响。该守卫仍是尽力 而为的检查,并非隔离边界。([#6930]) +- **沙箱:** 启用 host bash 时,本地路径守卫重新接受 awk 字段运算,例如 + `awk '{print $NF/2}' data.txt`、`awk '{print $sum/$n}' data.txt` 和 `($2+$3)/2`。 + 自 [#6930] 起,除非两侧都是数字,每个 `$NAME/` 都会被当作以变量为前缀的主机路径, + 而 `)` 后的 `/` 此前一直被视为绝对路径。现在 `awk`、`gawk`、`mawk` 或 `nawk` + 的单引号内联程序中的 `$` 或 `/` 可以豁免,因为 bash 不会展开其中的内容,awk 则将其 + 解释为字段引用或除法;程序可位于 `-F`、`-v` 等选项之后,命令词按 shell 的方式定位: + 跳过赋值前缀、将路径简化为文件名,也覆盖 `$(...)` 内部。对绝对路径扫描,仅豁免 + `/2` 或 `/NR` 这类单段匹配,`/a/b` 形式即使在 awk 代码中也仍被拒绝。awk 字符串 + 字面量、`-v` 等选项、输入操作数、双引号程序以及由 `sh -c` 或 `eval` 重新读取的文本 + 仍会被扫描。可能重新定义 `awk` 或重新读取带引号文本的命令(`alias`、`function`、 + `name()`、`eval`、`source`、`.`、`hash`、`PATH=`、heredoc)、扫描器未建模的语法 + (反斜杠换行、反引号、`$'...'`、未配对的 `)`),以及 `"` 可能位于 awk 正则字面量 + 中的程序都不享受豁免;awk 字符串字面量中的 `/` 和 `#` 按普通文本处理。 + (issue #7021, [#7023]) - **沙箱:** 在本地沙箱中,`ls` 现在接受 `/mnt/user-data` 根目录本身,并像 AIO 一样 列出 `workspace`、`uploads` 和 `outputs`。提供方有意映射了这个根目录,但工具层只允许 其下的路径,因此返回 `Permission denied`(带结尾斜杠时来自内部的 @@ -4615,6 +5227,31 @@ ### 安全 +- **infoquest:** 通过共享公网 URL 策略筛查自然搜索、新闻与图片结果的 URL,在其 + 到达模型前丢弃非公网及不安全引用。([#7031]) + +- **检查点:** 清理字面线程命名空间时,转义 Redis glob 元字符,并在删除前检查扫描 + 到的键是否属于该字面前缀。自定义前缀不再删除其他命名空间的缓存。([#6709]) + +- **渠道:** 通过共享的失败关闭辅助函数解析 Slack 与钉钉的 `allowed_users`。无效 + 或为空的配置条目不再静默关闭访问限制,带填充空白的 ID 会被归一化。([#6742]) + +- **图片搜索:** 共享地址检查前先归一化 Unicode 主机名点分隔符,拒绝伪装的回环、 + 私有、元数据及其他被阻止的字面主机地址,同时保留已接受 URL 的原始写法。([#6819]) + +- **MCP:** 发现错误日志不再包含可能携带凭据的异常消息与堆栈,仅保留服务器名与 + 异常类型,不改变发现失败处理。([#6794]) + +- **图片搜索:** 在 DuckDuckGo、Brave 和 Serper 间共享公网结果 URL 筛查,包括缩略图 + 回退与内嵌 IPv4 检查。拒绝多播、NAT64 回环等被阻止的字面地址;该纯字符串筛查 + 不解析 DNS。([#6740]) + +- **QQ:** 通过共享的失败关闭辅助函数解析标量与集合形式的 `allowed_users`,避免 + 逐字符 ID、按映射键授权,以及无效配置限制导致的宽松回退。([#6730]) + +- **前端:** 只接受结构化子智能体状态映射自身的键。`constructor` 与 `__proto__` + 等未知原型名称现在使用现有的进行中回退,不附加结果/错误元数据。([#6669]) + - **技能:** 所有已登录用户都能调用的 `GET /api/skills`、`GET /api/skills/custom` 和 `GET /api/skills/{name}`,其 `500` 响应的 detail 不再包含原始异常文本。此前 `extensions_config.json` 格式错误或不可读时,这三个接口都会在响应中返回该文件的 @@ -4638,20 +5275,6 @@ 不做部分晋升,无效模式仍回退到字面匹配,`select:` 保持精确、区分大小写且不设上限。 ([#6676]) -- **社区工具:** 委托式 `web_fetch`/`web_capture` 后端默认失败关闭。 - Browserless、Crawl4AI、Firecrawl 与 fastCRW 在后端自己的网络命名空间中解析 - 目标 URL,针对目标 URL 的 SSRF 屏障无法端到端生效。现在每个入口在委托之前 - 先筛查其解析出的后端 base URL(配置键、环境变量回退与默认值):公网后端 - 照常工作;回环、私有或无法验证的后端会被拒绝,除非运维确认其出网隔离。 - **升级提示:** 使用文档默认配置的部署(Browserless 位于 - `http://localhost:3032`、Crawl4AI 位于 `http://localhost:11235`,或经 - `base_url`/`CRW_API_URL` 自建的 Firecrawl/fastCRW)会在 - `web_fetch`/`web_capture` 上遇到委托错误,直到把后端指向其公网地址,或在 - 隔离后端出网之后在每个工具配置中设置 `network_isolation_confirmed: true`。 - `make doctor` 会对被拒绝的后端配置发出警告,包括 `CRW_API_URL` 覆盖。 - `allow_private_addresses` 仍然只控制目标 URL。参见[部署指引](backend/docs/CONFIGURATION.md#delegated-fetch-backend-isolation)。 - ([#6531]) - - **路径:** 上传、新建沙箱路径与新建技能支持文件路径现在拒绝扩展名前用 ASCII 空格 填充的 Windows 保留设备名主干(`NUL .txt`、`COM1 .log`)。此前共享的文件名可 移植性防护在第一个点处切分、把空格留在主干里,因而不再匹配保留名称集合,放行了 @@ -4889,6 +5512,20 @@ 文件。此前带一个杂散字节的 `hooks/install.jse` 既得不到静态分析,也 不经过可执行代码审查。([#6321]) +- **社区工具:** 委托式 `web_fetch`/`web_capture` 后端默认失败关闭。 + Browserless、Crawl4AI、Firecrawl 与 fastCRW 在后端自己的网络命名空间中解析 + 目标 URL,针对目标 URL 的 SSRF 屏障无法端到端生效。现在每个入口在委托之前 + 先筛查其解析出的后端 base URL(配置键、环境变量回退与默认值):公网后端 + 照常工作;回环、私有或无法验证的后端会被拒绝,除非运维确认其出网隔离。 + **升级提示:** 使用文档默认配置的部署(Browserless 位于 + `http://localhost:3032`、Crawl4AI 位于 `http://localhost:11235`,或经 + `base_url`/`CRW_API_URL` 自建的 Firecrawl/fastCRW)会在 + `web_fetch`/`web_capture` 上遇到委托错误,直到把后端指向其公网地址,或在 + 隔离后端出网之后在每个工具配置中设置 `network_isolation_confirmed: true`。 + `make doctor` 会对被拒绝的后端配置发出警告,包括 `CRW_API_URL` 覆盖。 + `allow_private_addresses` 仍然只控制目标 URL。参见[部署指引](backend/docs/CONFIGURATION.md#delegated-fetch-backend-isolation)。 + ([#6531]) + - **脚本:** 本地 `make dev` / `make start` 改为绑定回环地址。此前 `serve.sh` 和 `backend/Makefile` 以 `--host 0.0.0.0` 启动 Gateway,`nginx.local.conf` 监听所有网卡,Next.js 在 Windows 之外也沿用监听所有网卡的默认值,因此在局域网 @@ -4940,6 +5577,10 @@ ### 文档 +- **扩展:** 新增示例编写与打包指南,以及 `scripts/check_extension.py PACKAGE`。 + 该工具构建临时 wheel,在安装前检查入口点、Python 语法、API 依赖兼容性与浏览器 + 资源。检查器运行可信构建后端,不导入扩展,也不改变部署配置。([#6755]) + - **文档:** 新增韩语 README(`README_ko.md`),完整翻译当前英文 README。标题、表格和 链接与英文版一一对应,所有代码块和行内代码保持逐字节一致,只翻译正文。`README.md` 及其他译本的语言切换行和 `AGENTS.md` 的译本列表现已链接到该文件。 @@ -5069,6 +5710,29 @@ ### 内部改进 +- **前端:** 移除已弃用且未使用的 `hast` 和 `@types/gsap` 包。现有 `@types/hast` + 与 GSAP 自带类型继续提供所需声明。([#7108]) + +- **测试:** Windows 上跳过仅适用于 POSIX 的技能变更用例,保留可移植覆盖,并在 + 数据库删除测试前释放 fixture 的池化 SQLite 连接。([#7154]) + +- **基准测试:** 为独立沙箱基准新增可选的 OpenSandbox 覆盖,通过生产提供方测试 + 冷/暖复用、副本压力与空闲回收。清理失败会产生关闭失败证据,不再生成成功的基准 + 汇总。([#7059]) + +- **测试:** 将允许列表中的 Windows 基础系统与临时目录环境变量传给隔离的 + live-policy pytest 子进程,让解释器可以初始化,同时保留凭据隔离。([#6439]) + +- **测试:** 修复 Windows 宿主上命令执行、二进制读取、Lark 文件模式、技能审查和 + 扩展归档检查中的六处 fixture 与断言失败,保留原有行为契约。([#6787]) + +- **CI:** 相关示例、宿主代码、依赖、检查器或工作流变更时,对每个内置示例运行统一 + 扩展打包检查,验证真实 wheel 与浏览器资源。([#6788]) + +- **MCP:** 暴露按服务器划分的发现结果,包含完整包装的工具组与 stdio 绑定所有权。 + 保留现有有序扁平化公共 API,并区分成功但零工具的发现与失败,为选择性缓存提供 + 前置能力。([#6734]) + - **deps:** 升级 `/backend` 中的 `lark-oapi`:1.5.5 -> 1.7.3。([#6665]) - **模型:** 让推理内容捕获只有一个归属。`patched_mimo` 和 `patched_stepfun` 两个 @@ -9463,6 +10127,8 @@ DeerFlow 2.0 是围绕"超级智能体"框架的彻底重写,核心包含子 [#6746]: https://github.com/bytedance/deer-flow/pull/6746 [#6781]: https://github.com/bytedance/deer-flow/pull/6781 [#6785]: https://github.com/bytedance/deer-flow/pull/6785 +[#6798]: https://github.com/bytedance/deer-flow/pull/6798 +[#6836]: https://github.com/bytedance/deer-flow/pull/6836 [#6843]: https://github.com/bytedance/deer-flow/pull/6843 [#6844]: https://github.com/bytedance/deer-flow/pull/6844 [#6852]: https://github.com/bytedance/deer-flow/pull/6852 @@ -9481,3 +10147,189 @@ DeerFlow 2.0 是围绕"超级智能体"框架的彻底重写,核心包含子 [#7123]: https://github.com/bytedance/deer-flow/pull/7123 [#7155]: https://github.com/bytedance/deer-flow/pull/7155 [#7205]: https://github.com/bytedance/deer-flow/pull/7205 +[#5645]: https://github.com/bytedance/deer-flow/pull/5645 +[#6051]: https://github.com/bytedance/deer-flow/pull/6051 +[#6439]: https://github.com/bytedance/deer-flow/pull/6439 +[#6483]: https://github.com/bytedance/deer-flow/pull/6483 +[#6579]: https://github.com/bytedance/deer-flow/pull/6579 +[#6628]: https://github.com/bytedance/deer-flow/pull/6628 +[#6630]: https://github.com/bytedance/deer-flow/pull/6630 +[#6648]: https://github.com/bytedance/deer-flow/pull/6648 +[#6669]: https://github.com/bytedance/deer-flow/pull/6669 +[#6690]: https://github.com/bytedance/deer-flow/pull/6690 +[#6693]: https://github.com/bytedance/deer-flow/pull/6693 +[#6699]: https://github.com/bytedance/deer-flow/pull/6699 +[#6700]: https://github.com/bytedance/deer-flow/pull/6700 +[#6701]: https://github.com/bytedance/deer-flow/pull/6701 +[#6709]: https://github.com/bytedance/deer-flow/pull/6709 +[#6714]: https://github.com/bytedance/deer-flow/pull/6714 +[#6716]: https://github.com/bytedance/deer-flow/pull/6716 +[#6717]: https://github.com/bytedance/deer-flow/pull/6717 +[#6719]: https://github.com/bytedance/deer-flow/pull/6719 +[#6727]: https://github.com/bytedance/deer-flow/pull/6727 +[#6729]: https://github.com/bytedance/deer-flow/pull/6729 +[#6730]: https://github.com/bytedance/deer-flow/pull/6730 +[#6731]: https://github.com/bytedance/deer-flow/pull/6731 +[#6732]: https://github.com/bytedance/deer-flow/pull/6732 +[#6733]: https://github.com/bytedance/deer-flow/pull/6733 +[#6734]: https://github.com/bytedance/deer-flow/pull/6734 +[#6739]: https://github.com/bytedance/deer-flow/pull/6739 +[#6740]: https://github.com/bytedance/deer-flow/pull/6740 +[#6741]: https://github.com/bytedance/deer-flow/pull/6741 +[#6742]: https://github.com/bytedance/deer-flow/pull/6742 +[#6747]: https://github.com/bytedance/deer-flow/pull/6747 +[#6749]: https://github.com/bytedance/deer-flow/pull/6749 +[#6753]: https://github.com/bytedance/deer-flow/pull/6753 +[#6754]: https://github.com/bytedance/deer-flow/pull/6754 +[#6755]: https://github.com/bytedance/deer-flow/pull/6755 +[#6756]: https://github.com/bytedance/deer-flow/pull/6756 +[#6757]: https://github.com/bytedance/deer-flow/pull/6757 +[#6762]: https://github.com/bytedance/deer-flow/pull/6762 +[#6764]: https://github.com/bytedance/deer-flow/pull/6764 +[#6768]: https://github.com/bytedance/deer-flow/pull/6768 +[#6772]: https://github.com/bytedance/deer-flow/pull/6772 +[#6774]: https://github.com/bytedance/deer-flow/pull/6774 +[#6776]: https://github.com/bytedance/deer-flow/pull/6776 +[#6779]: https://github.com/bytedance/deer-flow/pull/6779 +[#6782]: https://github.com/bytedance/deer-flow/pull/6782 +[#6783]: https://github.com/bytedance/deer-flow/pull/6783 +[#6787]: https://github.com/bytedance/deer-flow/pull/6787 +[#6788]: https://github.com/bytedance/deer-flow/pull/6788 +[#6791]: https://github.com/bytedance/deer-flow/pull/6791 +[#6793]: https://github.com/bytedance/deer-flow/pull/6793 +[#6794]: https://github.com/bytedance/deer-flow/pull/6794 +[#6795]: https://github.com/bytedance/deer-flow/pull/6795 +[#6796]: https://github.com/bytedance/deer-flow/pull/6796 +[#6799]: https://github.com/bytedance/deer-flow/pull/6799 +[#6800]: https://github.com/bytedance/deer-flow/pull/6800 +[#6803]: https://github.com/bytedance/deer-flow/pull/6803 +[#6804]: https://github.com/bytedance/deer-flow/pull/6804 +[#6806]: https://github.com/bytedance/deer-flow/pull/6806 +[#6808]: https://github.com/bytedance/deer-flow/pull/6808 +[#6810]: https://github.com/bytedance/deer-flow/pull/6810 +[#6811]: https://github.com/bytedance/deer-flow/pull/6811 +[#6812]: https://github.com/bytedance/deer-flow/pull/6812 +[#6813]: https://github.com/bytedance/deer-flow/pull/6813 +[#6817]: https://github.com/bytedance/deer-flow/pull/6817 +[#6819]: https://github.com/bytedance/deer-flow/pull/6819 +[#6821]: https://github.com/bytedance/deer-flow/pull/6821 +[#6823]: https://github.com/bytedance/deer-flow/pull/6823 +[#6824]: https://github.com/bytedance/deer-flow/pull/6824 +[#6827]: https://github.com/bytedance/deer-flow/pull/6827 +[#6828]: https://github.com/bytedance/deer-flow/pull/6828 +[#6829]: https://github.com/bytedance/deer-flow/pull/6829 +[#6831]: https://github.com/bytedance/deer-flow/pull/6831 +[#6832]: https://github.com/bytedance/deer-flow/pull/6832 +[#6834]: https://github.com/bytedance/deer-flow/pull/6834 +[#6838]: https://github.com/bytedance/deer-flow/pull/6838 +[#6839]: https://github.com/bytedance/deer-flow/pull/6839 +[#6845]: https://github.com/bytedance/deer-flow/pull/6845 +[#6846]: https://github.com/bytedance/deer-flow/pull/6846 +[#6848]: https://github.com/bytedance/deer-flow/pull/6848 +[#6850]: https://github.com/bytedance/deer-flow/pull/6850 +[#6855]: https://github.com/bytedance/deer-flow/pull/6855 +[#6857]: https://github.com/bytedance/deer-flow/pull/6857 +[#6858]: https://github.com/bytedance/deer-flow/pull/6858 +[#6861]: https://github.com/bytedance/deer-flow/pull/6861 +[#6863]: https://github.com/bytedance/deer-flow/pull/6863 +[#6868]: https://github.com/bytedance/deer-flow/pull/6868 +[#6870]: https://github.com/bytedance/deer-flow/pull/6870 +[#6871]: https://github.com/bytedance/deer-flow/pull/6871 +[#6878]: https://github.com/bytedance/deer-flow/pull/6878 +[#6880]: https://github.com/bytedance/deer-flow/pull/6880 +[#6882]: https://github.com/bytedance/deer-flow/pull/6882 +[#6885]: https://github.com/bytedance/deer-flow/pull/6885 +[#6886]: https://github.com/bytedance/deer-flow/pull/6886 +[#6891]: https://github.com/bytedance/deer-flow/pull/6891 +[#6893]: https://github.com/bytedance/deer-flow/pull/6893 +[#6894]: https://github.com/bytedance/deer-flow/pull/6894 +[#6898]: https://github.com/bytedance/deer-flow/pull/6898 +[#6900]: https://github.com/bytedance/deer-flow/pull/6900 +[#6901]: https://github.com/bytedance/deer-flow/pull/6901 +[#6903]: https://github.com/bytedance/deer-flow/pull/6903 +[#6904]: https://github.com/bytedance/deer-flow/pull/6904 +[#6907]: https://github.com/bytedance/deer-flow/pull/6907 +[#6910]: https://github.com/bytedance/deer-flow/pull/6910 +[#6914]: https://github.com/bytedance/deer-flow/pull/6914 +[#6916]: https://github.com/bytedance/deer-flow/pull/6916 +[#6917]: https://github.com/bytedance/deer-flow/pull/6917 +[#6918]: https://github.com/bytedance/deer-flow/pull/6918 +[#6919]: https://github.com/bytedance/deer-flow/pull/6919 +[#6920]: https://github.com/bytedance/deer-flow/pull/6920 +[#6923]: https://github.com/bytedance/deer-flow/pull/6923 +[#6924]: https://github.com/bytedance/deer-flow/pull/6924 +[#6927]: https://github.com/bytedance/deer-flow/pull/6927 +[#6929]: https://github.com/bytedance/deer-flow/pull/6929 +[#6931]: https://github.com/bytedance/deer-flow/pull/6931 +[#6932]: https://github.com/bytedance/deer-flow/pull/6932 +[#6934]: https://github.com/bytedance/deer-flow/pull/6934 +[#6935]: https://github.com/bytedance/deer-flow/pull/6935 +[#6939]: https://github.com/bytedance/deer-flow/pull/6939 +[#6945]: https://github.com/bytedance/deer-flow/pull/6945 +[#6946]: https://github.com/bytedance/deer-flow/pull/6946 +[#6948]: https://github.com/bytedance/deer-flow/pull/6948 +[#6950]: https://github.com/bytedance/deer-flow/pull/6950 +[#6951]: https://github.com/bytedance/deer-flow/pull/6951 +[#6952]: https://github.com/bytedance/deer-flow/pull/6952 +[#6953]: https://github.com/bytedance/deer-flow/pull/6953 +[#6957]: https://github.com/bytedance/deer-flow/pull/6957 +[#6959]: https://github.com/bytedance/deer-flow/pull/6959 +[#6961]: https://github.com/bytedance/deer-flow/pull/6961 +[#6967]: https://github.com/bytedance/deer-flow/pull/6967 +[#6969]: https://github.com/bytedance/deer-flow/pull/6969 +[#6971]: https://github.com/bytedance/deer-flow/pull/6971 +[#6973]: https://github.com/bytedance/deer-flow/pull/6973 +[#6975]: https://github.com/bytedance/deer-flow/pull/6975 +[#6977]: https://github.com/bytedance/deer-flow/pull/6977 +[#6980]: https://github.com/bytedance/deer-flow/pull/6980 +[#6981]: https://github.com/bytedance/deer-flow/pull/6981 +[#6984]: https://github.com/bytedance/deer-flow/pull/6984 +[#6990]: https://github.com/bytedance/deer-flow/pull/6990 +[#6992]: https://github.com/bytedance/deer-flow/pull/6992 +[#6995]: https://github.com/bytedance/deer-flow/pull/6995 +[#6998]: https://github.com/bytedance/deer-flow/pull/6998 +[#7001]: https://github.com/bytedance/deer-flow/pull/7001 +[#7002]: https://github.com/bytedance/deer-flow/pull/7002 +[#7004]: https://github.com/bytedance/deer-flow/pull/7004 +[#7014]: https://github.com/bytedance/deer-flow/pull/7014 +[#7017]: https://github.com/bytedance/deer-flow/pull/7017 +[#7018]: https://github.com/bytedance/deer-flow/pull/7018 +[#7020]: https://github.com/bytedance/deer-flow/pull/7020 +[#7023]: https://github.com/bytedance/deer-flow/pull/7023 +[#7024]: https://github.com/bytedance/deer-flow/pull/7024 +[#7031]: https://github.com/bytedance/deer-flow/pull/7031 +[#7033]: https://github.com/bytedance/deer-flow/pull/7033 +[#7035]: https://github.com/bytedance/deer-flow/pull/7035 +[#7039]: https://github.com/bytedance/deer-flow/pull/7039 +[#7042]: https://github.com/bytedance/deer-flow/pull/7042 +[#7051]: https://github.com/bytedance/deer-flow/pull/7051 +[#7053]: https://github.com/bytedance/deer-flow/pull/7053 +[#7057]: https://github.com/bytedance/deer-flow/pull/7057 +[#7058]: https://github.com/bytedance/deer-flow/pull/7058 +[#7059]: https://github.com/bytedance/deer-flow/pull/7059 +[#7061]: https://github.com/bytedance/deer-flow/pull/7061 +[#7065]: https://github.com/bytedance/deer-flow/pull/7065 +[#7074]: https://github.com/bytedance/deer-flow/pull/7074 +[#7075]: https://github.com/bytedance/deer-flow/pull/7075 +[#7076]: https://github.com/bytedance/deer-flow/pull/7076 +[#7078]: https://github.com/bytedance/deer-flow/pull/7078 +[#7084]: https://github.com/bytedance/deer-flow/pull/7084 +[#7093]: https://github.com/bytedance/deer-flow/pull/7093 +[#7106]: https://github.com/bytedance/deer-flow/pull/7106 +[#7108]: https://github.com/bytedance/deer-flow/pull/7108 +[#7112]: https://github.com/bytedance/deer-flow/pull/7112 +[#7116]: https://github.com/bytedance/deer-flow/pull/7116 +[#7117]: https://github.com/bytedance/deer-flow/pull/7117 +[#7122]: https://github.com/bytedance/deer-flow/pull/7122 +[#7127]: https://github.com/bytedance/deer-flow/pull/7127 +[#7140]: https://github.com/bytedance/deer-flow/pull/7140 +[#7141]: https://github.com/bytedance/deer-flow/pull/7141 +[#7144]: https://github.com/bytedance/deer-flow/pull/7144 +[#7148]: https://github.com/bytedance/deer-flow/pull/7148 +[#7150]: https://github.com/bytedance/deer-flow/pull/7150 +[#7151]: https://github.com/bytedance/deer-flow/pull/7151 +[#7152]: https://github.com/bytedance/deer-flow/pull/7152 +[#7154]: https://github.com/bytedance/deer-flow/pull/7154 +[#7163]: https://github.com/bytedance/deer-flow/pull/7163 +[#7167]: https://github.com/bytedance/deer-flow/pull/7167 +[#7170]: https://github.com/bytedance/deer-flow/pull/7170