v0.186.0
Upgrading from v0.185.0
- ACP-runtime agents now refuse fenced messages (#3846, security). A
tool_fenceis the tool allowlist a plugin surface such as Discord's peer path attaches to an untrusted party's message. On an agent whose chat runtime is an ACP coder, the fence was never applied, so the message ran with every tool. It is now refused, and the refusal is logged. If you relay untrusted parties to an ACP-runtime agent, route them to a graph-runtime agent instead. - Fence behaviour is consistent and stricter (#3908, #3926, #3939).
- The per-turn tool allowlist now covers every pass of a turn: goal continuations, HITL resumes and held messages.
- Work a fenced turn leaves behind stays fenced: background-job briefings, scheduled and
waitresumes, watch reactions, hooks and goals it sets. - Subagents a fenced turn delegates to run under their own allowlist intersected with the fence. A subagent whose allowlist doesn't overlap the fence now runs with no tools.
- A plain turn no longer inherits a fence left on its thread by an earlier turn.
- Redaction keeps delimiters (#3816).
KEY=secretvalues in tool output, traces and audit logs now stop at the first whitespace or closing quote, backtick or bracket, so redacted source still parses. A secret that itself contains one of those characters is redacted only up to it. Provider-shaped keys (sk-…,ghp_…and so on) are still caught whole by their own patterns. - No config changes are required.
Highlights
- Chat-turn reliability. About twenty fixes to the streaming, non-streaming (
/v1,/api/chat, plugin) and A2A turn drivers. The main ones:- The two drivers share one dispatch chain and one failure classifier, so
/v1and plugin turns recover from context-window overflow and run/<subagent>commands (#3805). Goal-driven and autonomous turns behave the same on both drivers (#3891). - Abandoned, closed or finished turns release their thread lock and flush their trace immediately (#3870, #3876, #3877).
- Failed turns are recorded on the right thread (#3871), and a no-reply turn is a failure on
/v1(#3873). - An ACP turn stops when its client goes away (#3837).
- Two approval-gated tools pausing at once no longer fail a goal turn (#3884).
- A paused HITL turn no longer hangs a fresh browser, and answering it no longer orphans its task (#3930, #3931).
- Three lifecycle leaks are closed: orphaned
/workflowruns, stranded server-turn controls and stale steering queues (#3933). - A turn's model override reaches its subagents and background jobs (#3944).
- Non-streaming telemetry rows get their trace id (#3945).
- One malformed SSE frame no longer kills the chat stream (#3811).
- The two drivers share one dispatch chain and one failure classifier, so
- Concurrent config writes no longer corrupt each other (#3941). Every thread shared one YAML parser. Two simultaneous delegate creates, or any config read on the event loop racing a write, could fail with
IndexErroror a spuriousParserError. - Windows
run_commandhandles quoted paths (#3813)."C:\Program Files\Tool\tool.exe" --versionno longer fails with "is not recognized" under the defaultcmdshell. - Console on the design system's radius and spacing scales (#3887, protoContent#525/#547).
- The console now uses
@protolabsai/design^0.11.0 and@protolabsai/ui^0.66.1. - Every console stylesheet reads the DS radius and half-step spacing tokens.
- A tree-wide guard test keeps literal radius and off-scale spacing values out.
- Remaining hand-rolled action buttons (mobile header, chat actions, calendar, keybinding reset, MCP catalog, org chart) are DS
Buttons (#3832, protoContent#551).
- The console now uses
- Smaller fixes:
fetch_urlreports a redirect loop instead of returning the redirect stub (#3817).- Native Codex (ChatGPT OAuth) turns work with Langfuse tracing on (#3928).
- An unknown goal verifier is refused on every entry point, and
/v1answers 502 for an unreachable gateway (#3946). onboard_projectsays when it re-cloned a registered project's missing checkout instead of reporting "reused, nothing changed" (#3643).
- Internal: background loops, chat session ops, turn telemetry and plugin wiring moved out of
server/chat.pyandserver/agent_init.py, and the console'slib/api.tswas split up (#3807, #3808, #3810, #3821; epic #3804). No behaviour change.
The full list is in CHANGELOG.md.
What's Changed
- refactor(server): extract background maintenance loops into server/maintenance_loops.py (#3807) by @mabry1985 in #3815
- refactor(tools): extract _session_id_from into tools/session.py (#3806) by @mabry1985 in #3814
- fix(chat): one pre-turn dispatch + failure classifier for both turn drivers (#3805) by @mabry1985 in #3812
- refactor(web): split lib/api.ts into routing, http and a2aStream modules (#3808) by @mabry1985 in #3811
- fix(run_command): hand cmd.exe the command line verbatim on Windows (#3802) by @mabry1985 in #3813
- fix(tools): fetch_url reports a redirect loop instead of the 30x stub by @mabry1985 in #3817
- refactor(chat): extract session ops to chat_session_ops.py, usage helpers to turn_telemetry.py (#3810) by @mabry1985 in #3819
- refactor(desktop): split src-tauri lib.rs into updater/navigation/sidecar/hotkeys modules by @mabry1985 in #3818
- refactor(web): split the console api object into per-domain modules by @mabry1985 in #3824
- refactor(tools): extract memory tools into tools/memory_tools.py (#3820) by @mabry1985 in #3825
- refactor(server): extract plugin wiring from agent_init into server/plugin_wiring.py (#3821) by @mabry1985 in #3826
- refactor(plugins): extract update checks from installer.py into updates.py (#3823) by @mabry1985 in #3827
- refactor(tools): extract scheduler/task/watch + goal tools from lg_tools.py (#3830) by @mabry1985 in #3833
- refactor(server): extract stores + inbox recovery from agent_init into server/stores.py (#3829) by @mabry1985 in #3834
- refactor(chat): extract the ACP runtime into server/chat_acp.py (#3828) by @mabry1985 in #3835
- fix(web): #551 action-button swaps + composite-button audit markers (recovered from 9 board cards) by @mabry1985 in #3832
- refactor(delegates): split adapters.py into base, a2a and acp_adapter modules (#3831) by @mabry1985 in #3836
- refactor(console): move ChatSessionSlot out of ChatSurface.tsx by @mabry1985 in #3842
- refactor(config): extract loader helpers into graph/config_load.py (#3840) by @mabry1985 in #3845
- refactor(tools): extract self-editing tools into tools/self_edit_tools.py (#3839) by @mabry1985 in #3843
- refactor(chat): extract the @-delegate room exchange into server/chat_rooms.py (#3838) by @mabry1985 in #3844
- fix(chat): refuse a fenced turn on an ACP runtime instead of running it unfenced by @mabry1985 in #3846
- refactor(chat): extract useAttachments + useSlashAutocomplete from ChatSessionSlot by @mabry1985 in #3851
- refactor(chat): extract turn control into server/turn_control.py (#3847) by @mabry1985 in #3854
- refactor(plugins): extract bundle install/uninstall into graph/plugins/bundles.py (#3849) by @mabry1985 in #3853
- refactor(server): extract settings apply into server/settings_apply.py (#3848) by @mabry1985 in #3852
- test(chat): cover image+large-text paste and a visionModel change between renders (#3855) by @mabry1985 in #3857
- fix(acp): stop an abandoned ACP turn before the runtime is released (#3837) by @mabry1985 in #3858
- refactor(server): make turn_control / agent_init the real patch points; widen seam guards (#3856) by @mabry1985 in #3859
- chore(web): remove verified-dead selectors from theme.css by @mabry1985 in #3865
- refactor(chat): extract useHitl + useSteerQueue from ChatSessionSlot by @mabry1985 in #3864
- ci: raise the Python tests job timeout from 15 to 25 minutes by @mabry1985 in #3868
- refactor(server): extract the shared pre-turn dispatch into server/chat_dispatch.py (#3861) by @mabry1985 in #3867
- test(chat): characterization tests for the turn drivers by @mabry1985 in #3869
- fix(chat): close the stream impl when the wrapper is closed early (#3870) by @mabry1985 in #3875
- refactor(server): move the streaming event loop into server/turn_stream.py (#3874) by @mabry1985 in #3878
- fix(a2a): close the turn stream before execute() returns (#3876) by @mabry1985 in #3879
- fix(chat): close inner turn generators with aclosing on early exit (#3877) by @mabry1985 in #3881
- refactor(server): decompose _run_turn_stream into a state object + per-event handlers (#3880) by @mabry1985 in #3882
- test(web): cover useSteerQueue's status→idle and task-id-change reconcile triggers by @mabry1985 in #3886
- fix(turn_stream): consume per-run bookkeeping at tool end; pin it with reused-run_id goldens by @mabry1985 in #3885
- test(acp): pin the abandoned-turn settle await; retrieve a dropped driver's late failure by @mabry1985 in #3887
- ci: rebalance the Windows test shards and raise their timeout to 35 min by @mabry1985 in #3889
- feat: web: bump @protolabsai/design ^0.11.0 + @protolabsai/ui ^0.66.1; tokenNameGuard accepts
_token names (protoContent#525/#547 step 3, card 1 foundation) by @mabry1985 in #3888 - feat: web: radius + spacing tokens in activity.css + agent/identity.css (protoContent#525/#547 step 3) by @mabry1985 in #3893
- test(goals): stop a verifier test from re-running the whole suite by @mabry1985 in #3895
- feat: web: radius + spacing tokens in chat-component.css + promptviewer.css (protoContent#525/#547 step 3) by @mabry1985 in #3894
- refactor(server): one shared goal loop + HITL auto-answer for both turn drivers (#3884) by @mabry1985 in #3890
- feat: web: radius + spacing tokens in chat/chat.css + hitl.css (protoContent#525/#547 step 3) by @mabry1985 in #3896
- feat: web: radius + spacing tokens in workflows.css + providers.css (protoContent#525/#547 step 3) by @mabry1985 in #3897
- feat: web: radius + spacing tokens in settings/settings.css + keybindings.css (protoContent#525/#547 step 3) by @mabry1985 in #3900
- feat: web: radius + spacing tokens in fleet-room.css + fleet-activity.css (protoContent#525/#547 step 3) by @mabry1985 in #3902
- feat: web: radius + spacing tokens in app/theme.css + docviewer.css (protoContent#525/#547 step 3) by @mabry1985 in #3899
- feat: web: spacing tokens in app/palette.css + app-crash.css (protoContent#547 step 3) by @mabry1985 in #3904
- ci: skip web E2E on PRs that touch nothing it reads; 4 Playwright workers by @mabry1985 in #3898
- feat: web: radius + spacing tokens in codeviewer/code-pane.css + fleet/fleet.css (protoContent#525/#547 step 3) by @mabry1985 in #3907
- feat: web: radius + spacing tokens in schedule.css + settings/snapshot.css (protoContent#525/#547 step 3) by @mabry1985 in #3905
- test: stop waiting out real sleeps, timeouts and backoff (13 files) by @mabry1985 in #3903
- test(web): trim redundant e2e cases and replace fixed sleeps with condition waits by @mabry1985 in #3909
- fix(chat): stamp the per-turn tool fence on every graph pass, including goal continuations by @mabry1985 in #3908
- test: stop paying for git repos and subprocesses tests don't need by @mabry1985 in #3910
- ci: run the Linux Python suite with pytest-xdist (-n auto) by @mabry1985 in #3915
- fix(chat): record a failed turn on the thread it ran on (#3871) by @mabry1985 in #3912
- fix(chat): no-reply turns fail structurally; auto-answered text reaches done (#3873) by @mabry1985 in #3914
- ci(windows): run only platform-sensitive tests on the Windows lane; nightly full run by @mabry1985 in #3906
- test(deck): wait on conditions, not fixed pauses, in the deck TUI tests by @mabry1985 in #3916
- test: remove redundant, duplicate and tautological tests (1231 -> 757) by @mabry1985 in #3901
- refactor(chat): move the non-streaming turn driver into server/turn_sync.py (#3917) by @mabry1985 in #3918
- test(fleet): pin remote-token persistence and graceful-before-force shutdown ordering by @mabry1985 in #3919
- test(oauth): route-level contract for the operator OAuth config routes by @mabry1985 in #3920
- feat: web: radius + spacing tokens in chat/tool-calls.css (protoContent#525/#547 step 3) by @mabry1985 in #3911
- feat: web: radius + spacing tokens in settings/plugins.css + pathpicker.css (protoContent#525/#547 step 3) by @mabry1985 in #3913
- feat: web: radius + spacing tokens in settings/devices.css + telemetry.css (protoContent#525/#547 step 3) by @mabry1985 in #3924
- feat: web: radius + spacing tokens in app/work.css + app-drawer.css (protoContent#525/#547 step 3) by @mabry1985 in #3922
- fix(goal): goal-loop drift between the chat turn drivers (#3891 F1/F2/F4/F5) by @mabry1985 in #3923
- feat: web: spacing tokens in mobile-shell.css + settings/delegates.css + watches.css (protoContent#547 step 3) by @mabry1985 in #3925
- fix(tracing): stamp Langfuse trace metadata only on gateway clients (#3928) by @mabry1985 in #3932
- feat: web: radius + spacing tokens in app/tools.css + goals/goals.css (protoContent#525/#547 step 3) by @mabry1985 in #3927
- fix(chat): tool-fence rules for streaming dispatch, resumes and held messages by @mabry1985 in #3926
- fix: five server gaps from dev smoke — failed-turn telemetry, aside 500, /v1 validation, /goal off, v0.3 tasks/get (#3929) by @mabry1985 in #3934
- fix(chat): surface a HITL ask after text on the non-streaming driver; pin two goal-loop mutations (#3931) by @mabry1985 in #3937
- fix: close three turn-lifecycle leaks (workflow runner, live server turns, steering queues) (#3933) by @mabry1985 in #3938
- feat: web: radius + off-scale spacing guard test over all console CSS (protoContent#525/#547 step 3, final) by @mabry1985 in #3936
- fix(config): one ruamel parser per thread — concurrent config reads/writes corrupted each other by @mabry1985 in #3941
- fix(hitl): reattach settles a paused task off its snapshot; a HITL answer continues the parked task (#3930) by @mabry1985 in #3935
- ci: regenerate the Windows pytest-split duration seed on a Windows runner by @mabry1985 in #3921
- test(orgchart): start every test with no ledger on STATE (order-dependent failures) by @mabry1985 in #3942
- fix(chat): unfenced turns start unfenced; background nudges keep their origin's tool fence by @mabry1985 in #3939
- fix(subagents): one model precedence for task(), slash runs and background jobs (#3944) by @mabry1985 in #3948
- fix(telemetry): trace ids + A2A statuses on non-streaming rows; failed background jobs keep their error (#3945) by @mabry1985 in #3947
- fix: reject unknown goal verifiers everywhere; /v1 502 for an unreachable gateway; smoke minors (#3946) by @mabry1985 in #3949
- fix(redaction): env-var values stop at a closing quote/backtick — redacted source stays parseable (#3816) by @mabry1985 in #3952
- fix(onboard): say the checkout was missing and re-cloned, not "reused, nothing changed" (#3643) by @mabry1985 in #3953
Full Changelog: v0.185.0...v0.186.0