2302 Commits

Author SHA1 Message Date
Xiao Hou
830c8ff6f1
fix(runs): trim event_types filter entries before querying (#7758)
* fix(runs): trim event_types filter entries before querying

* style(runs): compute the trimmed event type once per entry

Addresses the review nit on #7758: use the walrus pattern already present
in this file (lines 657 and 1658) instead of stripping each entry twice.

No behavior change.

---------

Co-authored-by: gouyu-hou <gouyu-hou@users.noreply.github.com>
Co-authored-by: gouyu-hou <213296172+gouyu-hou@users.noreply.github.com>
2026-11-01 23:27:00 +08:00
onhm
51f732304a
test(channels): drop the POSIX-only utime flag that breaks 9 tests on Windows (#7750)
* test(channels): drop the POSIX-only utime flag that breaks 9 tests on Windows

os.utime(..., follow_symlinks=False) is not implemented on Windows, so every test in
tests/test_channel_credential_staging.py that ages a staging file dies in _age before
it exercises anything (NotImplementedError). CI runs backend unit tests on ubuntu only,
so this never surfaced. Every file aged here is a regular file, and the other 15+
os.utime call sites in the suite already omit the flag.

Verified on Windows 11 / Python 3.12: 9 failed, 2 passed before; 11 passed after.

* test(channels): keep the symlink aging the flag was there for

Review follow-up on #7750. Dropping follow_symlinks=False kept Windows green but
quietly lost POSIX coverage: _age(link) in the os.name != "nt" block used to stamp the
symlink's own mtime two days into the past, and without the flag os.utime follows the
link and ages backup.tmp instead. cleanup_stale_credential_staging keeps that symlink
alive through its entry.stat(follow_symlinks=False) + S_ISREG type guard, and with a
fresh mtime the age guard alone would retain it too, so the test no longer proved that
an old staging-pattern symlink is spared by the type check.

Pass the flag through instead of hard-coding it: _age(path, *, follow_symlinks=True)
forwards it, and only the POSIX-only symlink call site asks for follow_symlinks=False.
Windows never passes it, so os.utime still cannot raise NotImplementedError there.

Also corrects the comment: _age also ages a directory, so "every file aged here is a
regular file" overstated the case. os.utime on a directory works on Windows; the flag
only matters for the symlink below.

Verified on Windows 11 / Python 3.12: 11 passed.

Addresses review feedback on #7750.

---------

Co-authored-by: luoyi0000 <luoyi0000@users.noreply.github.com>
2026-11-01 23:25:44 +08:00
Evan
be39a8a879
fix(runtime): resume children paused for a withdrawn steer (#7753)
* fix(runtime): resume children paused for a withdrawn steer

wait_tool pauses every child as soon as a steer is pending, but only a
delivered steer sets steering_active, the flag finish_graph needs before it
resumes them. Removing the steer before delivery left the children parked
and the run waiting on them.

Release the children when deliver finds no input and no steer is in
progress. They stay paused during later model turns of a delivered steer.

* fix(runtime): release children paused by a steer withdrawn mid-turn

The steering_active guard skipped the release whenever another steer was
being handled. A child started during that turn is outside its
interrupted_children snapshot, so nothing resumed it after a second steer
was withdrawn and finish_graph waited forever.

Release every child a delivered steer does not hold. Each deliver re-takes
that snapshot, so a paused child outside it can only belong to a withdrawn
steer.

* fix(runtime): keep a replacement reusing a call ID out of the held steer

interrupted_children stores call IDs, and child() can replace a closed gate under the same ID. The replacement then looked held by an earlier delivered steer, so a withdrawn steer left it paused forever in a replaced turn. Drop the ID when its gate is replaced.
2026-11-01 23:18:49 +08:00
Totoro
a17e5694cc
fix(sandbox): stop owned command processes when a run is cancelled (#7772)
* fix(sandbox): stop owned command processes when a run is cancelled

* fix(sandbox): handle incomplete AIO output responses

---------

Co-authored-by: Totoro-qaq <279883115+Totoro-qaq@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-11-01 23:09:25 +08:00
一片一片
38e6be638b
fix(memory): tolerate unbounded stored fact confidence (#7764)
* fix(memory): tolerate unbounded stored fact confidence

A stored memory fact can carry a JSON integer such as 10**400. float() on it
raises OverflowError in _coerce_source_confidence and in the dedup merge
comparison, aborting the whole update cycle even though both sites already
handle every other unusable confidence. Treat the overflow like a missing or
non-finite value: 0.5 for ranking, 0.0 for the merge comparison.

* fix(memory): harden the remaining fact-confidence coercions

The import normalizer, prompt builder and relevance scorer each coerce a
stored fact confidence with float() and caught only TypeError/ValueError, so
an unbounded JSON integer such as 10**400 raised OverflowError: import failed
before the updater fallbacks ran, and prompt/relevance ranking could abort.
Catch OverflowError and take the existing defaults; document the full set of
coercions.
2026-11-01 15:04:16 +08:00
alexcastgonz
31e7b4ae4f
fix(mcp): keep a tool argument named runtime out of LangGraph's runtime injection (#7677)
* fix(mcp): keep a tool argument named runtime out of LangGraph's runtime injection

The pooled stdio wrapper and the background-submit wrapper took LangGraph's
ToolRuntime in a parameter called `runtime`. ToolNode injects by that name, so a
tool whose own input schema has a `runtime` property had the model's value
replaced by the ToolRuntime and then lost: the server received the other
arguments only, and TaskSubmitRequest.arguments missed it too.

Name the injected parameter `deerflow_runtime` in both wrappers (it is still
detected through its ToolRuntime annotation) and read it under that name in the
personal-MCP ownership guard. Existing tests that call the wrappers pass the new
name; two ToolNode tests cover a `runtime` business argument on each path.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(mcp): read the injected runtime under the right name in the personal-tool guard

The personal-tool ownership guard read kwargs["deerflow_runtime"], but only
the pooled stdio wrapper was renamed; personal HTTP/SSE tools still carry
langchain-mcp-adapters' `runtime` parameter, so the guard never saw the
authoritative runtime user for them. Look the parameter name up per tool, and
update the mcp AGENTS.md note on how the runtime is injected.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 12:45:14 +08:00
Hyeonsang Cho
9a49fb2bb3
fix(clarification): keep each question when a provider reuses a call ID (#7762)
* fix(clarification): keep each question when a provider reuses a call ID

The clarification ToolMessage ID, which is also the human-input
request_id, was clarification:{tool_call_id}. Providers that number
calls per response reuse call_0 across turns, so a later question took
the earlier one's ID: add_messages replaced the earlier question in
place and left the new call without a result.

Add a digest of the issuing AIMessage ID. A retry of the same call comes
from the same AIMessage and keeps its ID; without that message in state
the ID keeps its previous form.

* docs(changelog): reference #7762 for the clarification call ID fix
2026-11-01 12:41:34 +08:00
yetuge
35656d6a9f
fix(agents): ignore malformed entries in a serialized MCP routing index (#7751)
* fix(agents): ignore malformed entries in a serialized MCP routing index

`McpRoutingMiddleware._normalize_index` documents that it accepts "arbitrary
serialized routing data, not only the output of the builder", but two shapes
escaped the coercion and raised instead:

- an entry that is not a mapping (`str`, `list`, `None`, a number) reached
  `.get` and raised `AttributeError`;
- a non-finite `priority` raised `OverflowError` from `int()` — JSON accepts
  `Infinity`/`-Infinity` literals, so a hand-edited or foreign index can carry
  one.

The middleware is constructed per run, so either shape fails every model call
in that process instead of the entry being ignored the way an entry with no
keywords already is.

Both now degrade to "not indexable": a non-mapping entry is skipped, and a
priority that cannot be a finite int falls back to 0 (the existing value for
`None`/non-numeric priorities). Valid entries are unchanged.

Tests cover each rejected shape, the control shapes that already degraded, and
the builder-shaped output that must stay identical. Dropping only the mapping
guard fails the non-mapping cases; dropping only `OverflowError` fails the
non-finite cases.

* fix(mcp): handle infinite routing priorities in the builder

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-11-01 08:08:08 +08:00
Evan
c6a3993695
fix(runtime): keep each parallel task's gate across a steer (#7755)
wait_tool reused the name gate for its pause loop, so every parallel task
returned the last child's result id and its done callback closed that
child's gate. The message reducer then dropped all but one pending result,
and the model was told that a running subagent had been interrupted.

Rename the loop variable so each call keeps its own gate.
2026-10-31 21:40:59 +08:00
lisry-1
e0f5483fdf
fix(goal): fall back gracefully for an unsupported reply locale (#7745)
* fix(goal): fall back gracefully for an unsupported reply locale

goal_reply_text and goal_status_text indexed _TEXT directly with the
caller's locale, so a locale outside NotificationLocale (en-US/zh-CN)
raised KeyError. The /connect handshake (connect_reply_text) normalizes
with supported_locale and falls back to en-US; the /goal replies must do
the same instead of surfacing an internal error to the user.

Normalize the locale in both public entry points. Adds tests pinning the
fallback for an unknown locale and the zh-CN wording for a supported one.

* style(tests): format goal status locale assertion

---------

Co-authored-by: lisry-1 <249596828+lisry-1@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-31 19:19:42 +08:00
Hyeonsang Cho
eb5d1e1880
fix(projects): keep referenced originals when the trash sweep walks a symlinked tree (#7732)
* fix(projects): keep referenced originals when the trash sweep walks a symlinked tree

The storage reconciliation protects each row's namespace by its resolved
path (project_document_path resolves symlinks) but walked the unresolved
documents directory. With a symlinked .deer-flow (no DEER_FLOW_HOME),
users/, users/{id}/ or projects/, no walked directory matched a protected
namespace, so the startup sweep and the lazy trash-listing sweep unlinked
live document originals older than 24 hours as orphans.

Walk each project's resolved documents directory so both sides compare
the same paths.

* docs(changelog): reference #7732 for the trash sweep symlink fix

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-31 19:16:50 +08:00
aduoge
12b2a9429c
fix(channels): surface Feishu upload log_id and missing keys (#7731)
* fix(channels): surface Feishu upload log_id and missing keys

* test(channels): cover Feishu upload key and log_id checks

* test(channels): cover non-str Feishu upload keys
2026-10-31 19:16:29 +08:00
Liu Hao
762b7188ab
fix(conversation): tolerate malformed event metadata (#7721)
* fix(conversation): tolerate malformed event metadata

* fix(gateway): guard malformed event metadata

* fix(gateway): guard malformed message kwargs

* fix(gateway): log malformed transcript metadata

* fix(gateway): ignore malformed message roles
2026-10-31 18:25:31 +08:00
hataa
3027ab6714
fix(persistence): normalize non-finite floats before every JSON column write (#7733)
* fix(persistence): normalize non-finite floats before every JSON column write

The shared ORM engine serialized JSON columns with the lenient json.dumps
default (allow_nan=True), and the sync agent-storage engine set no
json_serializer at all. A non-finite float reaching a JSON column — run
metadata merges caller-supplied values, goal_verdict and
token_usage_by_model carry model/provider numbers, and json.loads('1e400')
yields inf — was emitted as the bare NaN/Infinity token, which PostgreSQL
jsonb rejects as invalid JSON, failing the whole write with DataError.
SQLite silently accepts and round-trips the invalid token, so the failure
was postgres-only and environment-dependent.

Adds dumps_json_safe/json_safe_value to persistence/json_compat.py (same
None-normalization the canonical display serializer applies since #7670,
which explicitly does not cover persisted state) and wires it into both
engines' json_serializer. Regressions pin: nested non-finite floats
normalize everywhere, finite values/bools pass through unchanged, the
async engine kwargs and the sync agent engine (postgres only; SQLite takes
no json_serializer) both route through it.

* fix(persistence): normalize JSON across synchronous engines

* docs: keep frontend guidance within the CI size budget

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-31 18:12:32 +08:00
jswSpace
bee97022b1
fix(projects): defer trash cleanup when retention config is unavailable (#7683)
* fix(projects): preserve trash when retention config is unavailable

* test(projects): address trash retention review feedback

---------

Co-authored-by: jswSpace <198684035+jswSpace@users.noreply.github.com>
2026-10-31 18:08:11 +08:00
gouyu-hou
0f2f199b3d
fix(console): tolerate malformed usage counters and pricing (#7736)
* fix(console): tolerate malformed usage counters and pricing

* docs(routers): record console counter tolerance in the router contract

* fix(console): reject stored counters beyond the float range

A JSON integer is not bounded by the float range: 10**400 parses as an
exact int, so _token_count passed it through and _token_cost then raised
OverflowError on the division back to float, taking /usage, /stats and
/runs down with a 500 - the same failure mode the rest of this PR
removes for every other junk shape.

Reject counts whose float conversion is not finite inside the existing
try, so they coerce to 0 and the run falls back to its legacy totals.
10**30 stays usable.

---------

Co-authored-by: gouyu-hou <gouyu-hou@users.noreply.github.com>
Co-authored-by: gouyu-hou <213296172+gouyu-hou@users.noreply.github.com>
2026-10-31 18:05:16 +08:00
NanPan
793d1edabc
fix(projects): drain summary shutdown across caller cancellation (#7684) 2026-10-31 17:34:49 +08:00
Totoro
44e372dd7f
feat(runtime): support Queue and Steer during active Web runs (#7729)
* feat(runtime): add Queue and Steer for active Web runs

* style(frontend): format Queue and Steer controls

* fix(runtime): retain user Steer controls and order active inputs

* docs: add Chinese changelog entry for Queue and Steer

---------

Co-authored-by: Totoro-qaq <279883115+Totoro-qaq@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-31 11:35:36 +08:00
derrickLzw
51f0e2de1c
feat(extensions): scope configured middlewares to lead or subagent (#7661)
* feat(extensions): scope configured middlewares to lead or subagent

* fix(helm): synchronize configured middleware config schema version

* fix(extensions): require explicit configured middleware scope
2026-10-31 08:46:16 +08:00
Lucien
178a9ab458
fix(web): preserve tool-result identity when provider call IDs repeat (#7672)
* fix(web): preserve independent results when tool call IDs repeat

* fix(web): preserve leading results and idempotent result replay
2026-10-31 08:41:07 +08:00
Dragon ze
5d2749b05b
fix(gateway): read the live config off the loop for thread token usage (#7727)
* fix(gateway): read the live config off the loop for thread token usage

build_context_usage resolves the model capacity through deps.get_config,
which revalidates config.yaml and extensions_config.json on every call, so
each /threads/{id}/token-usage request paid that file IO on the shared
Gateway loop.

* docs(changelog): record the thread token-usage config read move

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-31 08:28:01 +08:00
yinx65588-boop
cdc3e92d6b
fix(streaming): isolate in-memory replay payloads (#7644)
* fix(streaming): isolate in-memory replay payloads

* docs(streaming): explain sentinel identity during replay

* docs(streaming): document replay payload ownership

---------

Co-authored-by: yinx65588-boop <yinx65588-boop@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-31 08:15:24 +08:00
mika
d50cbf8dc5
fix(browser): isolate egress DNS workers (#6301)
* fix(browser): isolate egress DNS workers

* fix(browser): release resolver slots after loop close

* test(browser): cover resolver isolation on production loop

* docs(browser): scope egress resolver guidance to browser automation

* test: approve browser automation guidance path

---------

Co-authored-by: mikamikasuki <211269698+mikamikasuki@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-30 22:18:54 +08:00
jswSpace
882433ae50
fix(subagents): recover expired attempts in paused batches (#7686)
* fix(subagents): recover expired attempts in paused batches

* test(subagents): target item reads in lease recovery race

---------

Co-authored-by: jswSpace <198684035+jswSpace@users.noreply.github.com>
2026-10-30 21:50:39 +08:00
Hyeonsang Cho
8062d4ba12
fix(scripts): include nginx logs in dev_multi_instance.sh logs all (#7723)
* fix(scripts): include nginx logs in dev_multi_instance.sh logs all

`logs all` selected only the two Gateway logs, the same as running
`logs` with no argument, so nginx's error and access logs never showed
up although the help lists all next to nginx. `all` now adds the nginx
logs, and the nginx selection also covers nginx.log, where the start
command's own output goes and which no option printed before.

* docs(changelog): reference #7723 for the dev_multi_instance logs fix

* test(scripts): pin dev_multi_instance logs when nginx never started

Cover the layout start_nginx leaves behind when it bails on a missing
binary or a busy port: only gateway-*.log exists, so `logs all` prints
the two Gateway files and `logs nginx` prints nothing, both exiting 0.
2026-10-30 21:48:31 +08:00
Fish
2488ba7c27
fix(agents): tolerate deeply nested JSON tool results (#7679)
* fix(agents): tolerate deeply nested JSON tool results

* test(agents): verify the deep JSON parser premise

Signed-off-by: Willem Jiang <willem.jiang@gmail.com>

---------

Signed-off-by: Willem Jiang <willem.jiang@gmail.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-30 20:29:15 +08:00
llb555
3f1438d4a0
fix(channels): publish Discord and WeChat JSON state atomically (#7595)
* fix(channels): publish Discord and WeChat JSON state atomically

* fix(channels): adopt the shared atomic publisher for both state writers

* test(channels): pin the cleanup-failure direction too

* test(channels): keep a platform-independent guard on the publish call shape

* style(tests): apply ruff format to the channel encoding test
2026-10-30 14:54:41 +08:00
Hyeonsang Cho
b4b2a68ee5
fix(memory): mask backend secrets in the memory config responses (#7665)
* fix(memory): mask backend secrets in the memory config responses

GET /api/memory/config and /api/memory/status returned
memory.backend_config as loaded. Config loading has already resolved
$VAR references by then, so a DeerMem extraction model api_key or a
Honcho api_key reached every caller with memory:read in plaintext,
which with authorization disabled (the default) is every signed-in
user.

MemoryConfigResponse now masks credential-named values (api_key,
*_token, password, authorization, ...) at any depth as "***". The
key is matched on its end, so knobs such as token_counting and
guaranteed_token_budget and the api_key_env variable name stay
readable, and unset values stay null or empty. The loaded config the
backend uses is not changed.

* docs(changelog): reference #7665 for the memory config secret masking fix

* refactor(gateway): share config secret masking between MCP and memory

The memory config masking forked the MCP router's key normalization
and recursive masker. Both now use app/gateway/secret_masking.py, and
each router keeps its own key rule: MCP matches credential terms
anywhere in the key, memory matches them at the end and keeps unset
values. MCP masking is unchanged.

The memory rule now also covers plural and cookie keys (api_keys,
secrets, passwords, cookies). Plural tokens stays out because
max_injection_tokens is a DeerMem knob. A secret-named container is
still masked whole, since its keys can be arbitrary names; the helper
docstring and a test now say so.

* docs(changelog): move the #7665 entry to Unreleased
2026-10-30 14:53:33 +08:00
Winoren
c50cdc5161
fix(uploads): resolve conversion settings in the parser worker (#7642) 2026-10-30 08:50:37 +08:00
RongJie G
9e6ce2f98e
fix(runtime): normalize non-finite floats in canonical serializer (#7670)
serialize_lc_object() passed floats through unchanged, so a non-finite
value (NaN/inf/-inf) survived serialization and broke the two display
paths that share it with opposite JSON policies: the SSE wire
(format_sse / Redis bridge use the lenient default and emit bare
NaN/Infinity tokens the langgraph-sdk/useStream decoder rejects,
breaking the live stream) and the REST surface (Starlette JSONResponse
uses allow_nan=False and raises, turning a thread read into HTTP 500).

Non-finite floats reach the serializer from ordinary runtime data:
json.loads("1e400") yields inf for a tool parsing external JSON, a
provider logprob of -inf for a zero-probability token, or a divide-by-
zero ratio. They round-trip inside Python and checkpoint persistence and
only fail at the JSON boundary.

Normalize non-finite floats to None and recurse into model_dump()/dict()
output so nested values (e.g. a message's response_metadata) are
normalized too. This is a display/wire normalization only; persisted
checkpoint state is never routed through this serializer. Finite floats
are unchanged.

Signed-off-by: CorgiBoyG <111257566+CorgiBoyG@users.noreply.github.com>
2026-10-30 08:49:30 +08:00
lihongyuan99
9e7448cabd
fix(changelog): define the missing [#7022] reference link (#7710)
Both change logs mention [#7022] in the workflow-turn-cap entry but neither
defines it, so the released page renders the literal text "[#7022]" next to a
working link for the fixing PR. #7022 is an issue, not a pull request, so the
definition targets issues/7022.

Add an offline guard for the whole class: every [#n] reference token needs a
definition, and every definition must aim at the same number in this repository
(commit permalinks, as used for deleted PRs, stay allowed).
2026-10-30 08:40:00 +08:00
SumEn
b86be89f09
fix(threads): preserve concurrent create idempotency in memory mode (#7691)
* fix(threads): preserve concurrent create idempotency in memory mode

* fix(threads): serialize detached run metadata creation

* docs(gateway): clarify metadata admission timeout budget

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-30 08:39:03 +08:00
haotianqi666
f7da737118
fix(memory): avoid replaying Honcho checkpoint history (#7687)
* fix(memory): avoid replaying Honcho checkpoint history

* fix(memory): harden Honcho capture lookups

---------

Co-authored-by: haotianqi666 <250384991+haotianqi666@users.noreply.github.com>
2026-10-30 07:33:41 +08:00
LingYi
c28e64fc8f
fix(memory): enforce the token budget when truncating summaries (#7709)
Signed-off-by: LingYi-Liang <270316896+LingYi-Liang@users.noreply.github.com>
Co-authored-by: LingYi-Liang <270316896+LingYi-Liang@users.noreply.github.com>
2026-10-30 07:32:51 +08:00
Lucien
15433dda2a
fix(browser): preserve the browser context after login popups close (#7674)
* fix(browser): preserve context when active popup closes

* fix(browser): focus recovered managed tabs and clarify session guidance
2026-10-30 07:20:02 +08:00
Cordis798
62de7f3425
perf(knowledge): bound concurrent WeKnora document checks (#7707)
Co-authored-by: Cordis798 <284918518+Cordis798@users.noreply.github.com>
2026-10-30 07:08:01 +08:00
dependabot[bot]
8d52d2541d
chore(deps): bump langgraph from 1.2.9 to 1.2.14 in /backend (#7703)
* chore(deps): bump langgraph from 1.2.9 to 1.2.14 in /backend

Bumps [langgraph](https://github.com/langchain-ai/langgraph) from 1.2.9 to 1.2.14.
- [Release notes](https://github.com/langchain-ai/langgraph/releases)
- [Commits](https://github.com/langchain-ai/langgraph/compare/1.2.9...1.2.14)

---
updated-dependencies:
- dependency-name: langgraph
  dependency-version: 1.2.14
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* test: make goal race saver compatible with LangGraph 1.2.14

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-30 06:42:38 +08:00
haotianqi666
81e1ab8dcc
fix(telegram): preserve group reply conversation context (#7654)
* fix(telegram): preserve group reply conversation context

* fix(telegram): log mapping outages once per streamed answer

---------

Co-authored-by: haotianqi666 <250384991+haotianqi666@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-30 00:16:45 +08:00
Totoro
8d11aeb97b
feat(subagents): configure thinking and reasoning effort for native workers (#7668)
* feat(subagents): add thinking_enabled and reasoning_effort config for sub-agents (#4875)

(cherry picked from commit b1083728b23504cb0f1d1a463f8db70c5ec1c5a7)

* fix: resolve CI failures for subagent thinking config PR

- Fix UnboundLocalError in task_tool.py: initialize parent_thinking_enabled
  and parent_reasoning_effort before the if runtime block
- Remove unused imports from test_subagent_thinking_config.py
  (SimpleNamespace, pytest, resolve_subagent_model_name)
- Fix import sorting in subagents_config.py and test file
- Add reasoning_effort: None to executor test assertion

(cherry picked from commit 187851e307b871937e48bb67ae1b34b8b69bf92d)

* fix: address review comments - remove parent inheritance, supports_thinking clamp, Literal type

- Remove parent_thinking_enabled/parent_reasoning_effort from metadata
  extraction in task_tool.py (backward compatible: subagents only think
  when explicitly configured)
- Add supports_thinking clamp in _create_agent to prevent cross-model
  mismatch errors
- Change SubagentConfig.reasoning_effort to Literal type
- Fix sandbox_state assignment that was accidentally removed
- Fix syntax errors in subagents_config.py (missing closing parens)
- Update all docstrings/comments from "inherit" to "no override"
- Simplify test helper and remove parent inheritance tests

(cherry picked from commit 74f9c659ef4a98bd1756109929ab0748fab82317)

* feat(subagents): adapt reasoning settings to current native workers

* fix(subagents): retain model context on reasoning rejection

* fix(subagents): preserve model-factory reasoning diagnostics

---------

Co-authored-by: Neon549 <neon549@users.noreply.github.com>
Co-authored-by: Totoro-qaq <279883115+Totoro-qaq@users.noreply.github.com>
2026-10-29 22:26:12 +08:00
LingYi
30aa601f6a
fix(runtime): isolate run admission from unrelated heartbeats (#7664)
Signed-off-by: LingYi-Liang <270316896+LingYi-Liang@users.noreply.github.com>
Co-authored-by: LingYi-Liang <270316896+LingYi-Liang@users.noreply.github.com>
2026-10-29 22:19:10 +08:00
Felix Shi
44b88151be
fix(skills): capture package digests without POSIX-only dir_fd (#7583)
* fix(skills): capture package digests without POSIX-only dir_fd

`capture_package` rejected every non-POSIX host, so `SkillMutationRuntime.state`
fell back to `"unsupported-" + uuid4().hex`. That digest differs on every call,
so `repository.observe()` recorded a mutation for an untouched package:
`mutation_seq` kept climbing and ABA detection could never match.

Walk the tree with `scandir` + `lstat` where `dir_fd`/`O_NOFOLLOW` are missing,
comparing the pre-open `lstat` against the opened descriptor before reading,
and leave the POSIX descriptor walk unchanged.

Windows 11 / Python 3.12: test_skill_asset_versions.py 5 failed -> 23 passed;
reverting this file alone brings the 5 failures back.

* docs(gateway): keep guidance below CI size budget

---------

Co-authored-by: Felix Shi <204130665+shi-felix@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-29 22:08:06 +08:00
Willem Jiang
6ca83a32cd
chore(release): keep deerflow-harness in the version-source lockstep (#7696)
* chore(release): keep deerflow-harness in the version-source lockstep

bump_version.sh now also rewrites backend/packages/harness/pyproject.toml
(deerflow-harness is a workspace member, so `uv lock` moves its
backend/uv.lock entry too), and verify_versions.sh gates on it in both
tag and mutual-equality modes. RELEASING.md and AGENTS.md describe the
five version sources.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* docs: keep version guidance within inherited size budget

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-10-29 21:11:45 +08:00
NanPan
5c4ba4d2fe
fix(mcp): drain compensation work during service shutdown (#7662)
* fix(mcp): drain compensation work during service shutdown

* test(mcp): make shutdown drain assertion deterministic

* fix(mcp): preserve shutdown drain through caller cancellation

* style(mcp): keep test module spacing consistent

* fix(mcp): report pending compensation tasks on shutdown timeout

* test(mcp): cover compensation observability on poller timeout
2026-10-29 14:40:09 +08:00
ShiYuan Xiong
f42076a005
fix(projects): preserve conversion outcomes through staging cleanup (#7659) 2026-10-28 22:07:44 +08:00
NanPan
f82f9b2829
fix(events): rebase RunEvent snapshot isolation onto current main (#7423) 2026-10-28 20:59:10 +08:00
Tsai Yuan
966aa9496a
fix(benchmark): validate sandbox timing options (#7651)
* fix(benchmark): validate sandbox timing options

* fix(benchmark): guard infinite idle reaping

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-28 20:47:59 +08:00
SumEn
c58c71f3fa
fix(runs): move thread index membership on snapshot replacement (#7622) 2026-10-28 20:47:01 +08:00
Hyeonsang Cho
f6a8f076ed
fix(tui): show picker labels as written instead of parsing markup (#7631)
* fix(tui): show picker labels as written instead of parsing markup

SelectScreen passed thread titles and model display names to Textual as
plain str, which Textual parses as content markup. A thread title such as
'Fix [/bold] in parser' raised MarkupError and exited the app whenever
/threads opened, and '[a]' vanished from the list. Wrap the title and
option labels in Rich Text so they render literally.

* docs(changelog): reference #7631 for the TUI picker markup fix

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-28 20:23:31 +08:00
hataa
a7d8971078
fix(docker): pin nginx to 1.31.2-alpine before the musl 1.2.6 pwritev2 build, closes #7615 (#7643)
Both shipped compose files used the floating nginx:alpine tag. When the
alias moved to the 1.31.3 alpine build (musl 1.2.6), nginx's pid-file
pwrite() started issuing pwritev2(RWF_NOAPPEND), which the default
seccomp profile of older Docker releases (and EOL kernels like CentOS 7)
does not allowlist. The master then dies with

    pwrite() "/run/nginx.pid" failed (1: Operation not permitted)

and the container restart-loops, so make docker-start / make up never
become healthy. The image cannot fix this (nginx/docker-nginx#1059);
1.31.2 is the last alpine build on musl 1.2.5, whose pwrite() still uses
pwrite64.

Pins both compose files to nginx:1.31.2-alpine in lockstep and adds a
regression test that rejects any floating nginx tag in either file.
2026-10-28 18:52:13 +08:00
asts
f79debed59
fix(mcp): reject unsupported inline audio results (#7628)
* fix(mcp): reject unsupported inline audio results

* fix(mcp): include MIME type in unsupported audio errors
2026-10-28 14:00:34 +08:00