fix(agent-editor): stop dropping behavior_policy.supports_team - #4176
Open
arnaud-moona wants to merge 3 commits into
Open
arnaud-moona wants to merge 3 commits into
arnaud-moona wants to merge 3 commits into
Conversation
arnaud-moona
requested review from
IceyLiu,
jiahe0510 and
kaizhou-lab
as code owners
August 25, 2026 05:15
arnaud-moona
force-pushed
the
fix/advanced-editor-drops-supports-team
branch
from
August 25, 2026 05:18
3de65a6 to
d792166
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
arnaud-moona
force-pushed
the
fix/advanced-editor-drops-supports-team
branch
3 times, most recently
from
August 25, 2026 10:46
e119786 to
b143ef5
Compare
The custom agent editor's advanced panel is a free-form JSON editor, but
`handleJsonChange` whitelists the keys it keeps. For `behavior_policy` it
only preserved `supports_side_question`, so typing
{ "behavior_policy": { "supports_team": true } }
looked accepted and was silently discarded on save — the field never
reached `/api/agents/custom`, which does accept it.
That flag gates team-mode eligibility and is seeded `false` for custom
agents, so a custom ACP agent could not be made team-selectable through
the UI at all. The only remaining routes are the HTTP API (unreachable
from outside the app since business endpoints require a session) or
editing aioncore's SQLite directly.
- parse `supports_team` alongside `supports_side_question`, building the
policy object incrementally so neither key clobbers the other;
- surface both keys in the skeleton JSON so the panel is
self-documenting — `supports_team` was otherwise undiscoverable;
- declare the field in `CustomAgentAdvancedOverrides` and
`BehaviorPolicy`, where it had been dropped while the backend still
reads it.
No behaviour change for agents that do not set the flag.
Follow-up to the previous commit, which fixed the dropped key without a regression test — the parsing lived in an inline `useCallback`, so it was not reachable from a unit test. - move the serialize/parse pair to `advancedOverrides.ts` (a .ts module, so the node-environment test does not pull React); - cover it in `tests/unit/settings/`: `supports_team` survives, both policy flags coexist, non-booleans are ignored, blanks are dropped, and the build → parse round-trip preserves what the panel shows. Behaviour is preserved, including two quirks now pinned by tests rather than left implicit: - valid JSON that is not an object (`"s"`, `null`) clears the error and keeps the previous bag, so the result is a three-way outcome (`ok` / `ignored` / `invalid`) rather than a nullable value; - an array parses as an empty bag, because `typeof [] === 'object'` has always let it through. Documented, not changed: this PR fixes a dropped key, not the panel's tolerance for odd input. Writing the tests caught the second point — the first draft asserted arrays were ignored, which would have been a silent behaviour change.
CI feedback: - Oxfmt reformatted `InlineAgentEditor.tsx` (one over-long line). Applied with the pinned oxfmt 0.41.0 so the hook is a no-op now. - Codecov flagged the patch: the remaining uncovered lines are the thin component-side binding, not the logic. `buildJsonFromAdvanced` was a `useCallback` wrapper around a module-level pure function — already stable across renders, so the indirection bought nothing and only added untestable lines. Calling `buildAdvancedJson` directly removes it and simplifies the effect's dependency array. oxlint reports 0 warnings / 0 errors on both new files.
arnaud-moona
force-pushed
the
fix/advanced-editor-drops-supports-team
branch
from
September 13, 2026 20:20
519789c to
c8acef2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The advanced panel of the custom agent editor is a free-form JSON editor, but
handleJsonChangewhitelists the keys it keeps. For
behavior_policyit preserved onlysupports_side_question, sotyping
{ "behavior_policy": { "supports_team": true } }validated, showed no error, and was silently discarded on save — the value never reached
/api/agents/custom, which does accept it.That flag gates team-mode eligibility and is seeded
falsefor custom agents, so a custom ACP agentcould not be made team-selectable through the UI at all, even when it advertises
agentCapabilities.mcpCapabilities.stdio: trueatinitialize. The only remaining routes were theHTTP API (business endpoints require a session, so unreachable from outside the app) or editing
aioncore's SQLite directly.
The change parses
supports_teamalongsidesupports_side_question, building the policy objectincrementally so neither key clobbers the other; surfaces both keys in the skeleton JSON so the panel
is self-documenting; and declares the field on
CustomAgentAdvancedOverridesandBehaviorPolicy,where it had been dropped while the backend still reads it.
Serialization moved to
advancedOverrides.tsso the round-trip is unit-testable — the parsing livedin an inline
useCallbackand was unreachable from a test. Behaviour is preserved, including twopre-existing quirks now pinned by tests rather than left implicit: valid JSON that is not an object
(
"s",null) clears the error and keeps the previous bag, hence a three-way outcome(
ok/ignored/invalid); and an array parses as an empty bag, becausetypeof [] === 'object'has always let it through.
Related Issues
team_capablefrom the handshake (backend-side): to be linkedType of Change
fix— Bug fix (non-breaking change which fixes an issue)feat— New feature (non-breaking change which adds functionality)perf— Performance improvementrefactor— Code restructuring (no behavior change)docs— Documentation updateAtomic PR Checklist (Rule 1)
fix(scope): subject(English)The three commits are the fix, its regression test, and the formatting pass — one change, not three.
Local Checks (Rule 3)
bun run format— changed files formatted; fullformat:checkpasses (2084 files)bun run lint— 0 errors (912 pre-existing repository warnings only)bunx tsc --noEmit— no type errorsbunx vitest run— 518 files passed, 1 skipped; 4,957 tests passed, 5 skipped, 0 failednode scripts/generate-i18n-types.js+node scripts/check-i18n.js)Runtime Verification
Screenshots
Not applicable; the panel already existed and its rendering is unchanged. The only visible difference
is that the skeleton JSON now lists
supports_teamalongsidesupports_side_question.Additional Context
Tests.
tests/unit/settings/advancedOverrides.test.tscovers the round-trip:supports_teamsurvives alone and alongside
supports_side_question, non-boolean flags are ignored rather thancoerced, blanks are still dropped, and
buildAdvancedJson→parseAdvancedOverridespreserves whatthe panel displays. Writing them caught a mistake in the first draft, which asserted arrays were
ignored — that would have been a silent behaviour change smuggled into a bug fix.
Coverage. Codecov flags the patch at 16%. The uncovered lines are the thin component-side binding
in
InlineAgentEditor.tsx, not the logic, which now lives in a separate module and is covered.Covering the remaining branches would require a DOM test mounting the whole editor (CodeMirror, Arco,
ipcBridge, the emoji picker) to exercise threeifs. Happy to add one if you would rather have it.Flaky test in CI, green locally. An earlier CI run on this branch failed on
tests/unit/renderer/mermaidBlockPanZoom.dom.test.tsx. The full suite passes locally on the samecommit (4,957 passed, 0 failed), so the failure is load-sensitive rather than a regression — and it
is unrelated either way: the test exists on
main, this branch neither adds nor modifies it, andMermaidBlockshares no code with the files changed here.The trace points at a race: the test captures
innerviadiagram.firstElementChildimmediatelyafter
findByTestId, so if the async mermaid render replaces that node the reference is detached andits
transformnever updates — which matches the observedscale(1)after a zoom-in click. Flaggingit in case it is worth hardening separately.
Scope. This makes the existing flag reachable. It does not address why a custom agent that
declares MCP stdio needs a manual flag at all, when
team_capableis documented as "MCP stdiocapable, computed by backend" — the stored
mcp_capabilitiescurrently keeps onlyhttpandsse,so the advertised
stdionever reaches the catalog. That belongs in the backend and is filedseparately.