Skip to content

fix(ai): provider is the primary key in the model picker sort - #2369

Merged
rbuergi merged 2 commits into
mainfrom
fix/2331-model-picker-provider-order
Aug 26, 2026
Merged

rbuergi merged 2 commits into
mainfrom
fix/2331-model-picker-provider-order

Conversation

@rbuergi

@rbuergi rbuergi commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes A per-model Order pin splits its provider's block in the model picker — one provider, two headers #2331 — a per-model Order pin (ModelOrdering.Defaults, used to promote one model to be
    the deployment default) split its provider's block in the model picker, because
    AgentPickerProjection.ProjectModels sorted by Order first and Provider second. When a
    provider's models don't all share one Order value, that isn't guaranteed to be contiguous — the
    provider rendered under two separate headers, with the pinned model stranded at the top.
  • Provider is now the primary sort key (mirrors ProjectAgents' GroupName-first sort), so every
    provider's models are contiguous by construction. Order is the tie-break inside the group —
    a pin still promotes its model to the top of its own provider's block, preserving the pin's
    intended effect without tearing the group apart.
  • The router (Auto) is pinned ahead of every concrete provider via an explicit IsRouter-first
    key, preserving its documented "sorts ahead of everything" intent (RouterOrder = -10) regardless
    of where "Auto" would otherwise land alphabetically. ObserveDefaultComposer's default-selection
    logic re-sorts by Order independently of this display order, so default resolution is
    unaffected.

Coordination check (per AGENTS.md)

MeshWeaver.AI is being carved out of core in a separate live effort (#2276). Checked
git log origin/main -- src/MeshWeaver.AI and every open PR's file list before editing — none
touch AgentPickerProjection.cs. Diff is scoped to that file, its test, and one What's New entry.

Related: #1880 (already closed separately)

While investigating, re-verified #1880 ("duplicate/mislabelled Azure Foundry provider group") end
to end and found all of it already resolved — not by this PR, so I closed it directly rather
than lumping it in here:

  • Defects 2 (slash-id loses its header) and 3 (stale seeded label) were code, fixed by fix(ai): group each model under its own provider in the model picker #1881
    (merged 2026-08-19). The old grouping mechanism that issue investigated
    (ThreadChatView.razor.cs's path-based ArrangePickerGroups) no longer exists in this repo — it
    left with Delete Blazor and the portal GUI from core #2293. Today's AgentPickerProjection.ProjectModels groups by the Provider string
    field, not by splitting the node path, so defect 2's failure mode can't recur by construction;
    AgentPickerModelOrderingTest (added here) exercises slash-containing ids for coverage against
    the current mechanism, replacing the regression test that moved out with the Blazor GUI.
  • Defect 1 (duplicate Provider/Azure / Provider/AzureFoundry nodes) was data. Verified live via
    MCP: Provider/Azure no longer exists, and Provider/AzureFoundry now carries
    name: "Azure Foundry" — both edits the issue asked for are done.

Test plan

  • dotnet build src/MeshWeaver.AI/MeshWeaver.AI.csproj -c Release -warnaserror — clean
  • dotnet build test/MeshWeaver.AI.Test/MeshWeaver.AI.Test.csproj -c Release -warnaserror — clean
  • New AgentPickerModelOrderingTest (3 tests) — green, pins: a pinned model stays inside its
    own provider's block; naturally interleaved provider Orders (no pin) still render one header
    per provider; the router leads regardless of alphabetical position
  • Re-ran the surrounding picker/model-resolution suites (AgentPickerQueryTest,
    AgentPickerQueriesTest, AgentPickerDeduplicationTest, AgentPickerUtilityFilterTest,
    AgentRosterContentShapeTest, AiResolutionSeamAuditTest, BuiltInLanguageModelProviderTest,
    AutoModelRouterTest, AutoRouterDispatchTest, ChatClientCredentialResolverTest,
    ModelTierCatalogTest, ModelPriceCatalogTest) — all green, no regressions
  • WhatsNewEntryIntegrityTest / DocumentationLinkIntegrityTest — green after adding the
    What's New entry

🤖 Generated with Claude Code

AgentPickerProjection.ProjectModels sorted by Order first and Provider
second, so a per-model Order pin (ModelOrdering.Defaults, promoting one
model to be the deployment default) could lift that model out of its
provider's contiguous run — the dropdown then rendered the same
provider under two separate headers with the pinned model stranded
between them.

Provider is now the primary key, mirroring ProjectAgents' GroupName-
first sort, so every provider's models are contiguous by construction.
Order becomes the tie-break INSIDE the group — a pin still promotes
its model to the top of its own provider's block, which is what the
pin is for. The router (Auto) is pinned ahead of every provider via an
explicit IsRouter-first key, preserving its "sorts ahead of everything"
intent (RouterOrder = -10) regardless of where "Auto" would otherwise
land alphabetically.

Adds AgentPickerModelOrderingTest covering: a per-model pin staying
inside its own provider's block, naturally interleaved provider Orders
(no pin involved) still rendering one header per provider, and the
router leading the list.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 26, 2026 12:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes model picker grouping so that models remain contiguous within their provider, even when individual models are “pinned” via a per-model Order override (as in #2331). It changes the projection sort order to group primarily by provider (with the Auto router forced to the top), and adds regression tests plus a What’s New entry documenting the user-visible fix.

Changes:

  • Update AgentPickerProjection.ProjectModels sorting to keep provider blocks contiguous, using Order only as an in-provider tie-break and forcing router models first.
  • Add AgentPickerModelOrderingTest to lock in contiguous provider grouping and router-first behavior.
  • Add a What’s New entry describing the model picker grouping fix.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/MeshWeaver.AI/AgentPickerProjection.cs Changes model picker sort order to keep providers contiguous and prioritize router models.
test/MeshWeaver.AI.Test/AgentPickerModelOrderingTest.cs Adds regression tests covering pinned models, interleaved orders, and router-first ordering.
src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-26-model-picker-groups-stay-together.md Documents the user-visible fix in the What’s New feed.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Append(null) on the (non-nullable) Provider string sequence raised
CS8625 under -warnaserror, which only Release/-warnaserror catches —
a plain Debug build passed. Count runs as 1 + the number of adjacent
pairs whose Provider differs; no sentinel needed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

    9 files  ± 0      9 suites  ±0   5m 9s ⏱️ - 1m 8s
2 017 tests +22  2 017 ✅ +25  0 💤  - 3  0 ❌ ±0 
2 570 runs  +23  2 570 ✅ +26  0 💤  - 3  0 ❌ ±0 

Results for commit 1fe2e3c. ± Comparison against base commit d9b59b6.

This pull request removes 651 and adds 673 tests. Note that renamed tests count towards both.
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_ExcludeUtility_AppendsUtilityFilter
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_NeitherSet_PlatformDefaultsOnly
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_OnlySpace_ListsSpacePlusPlatform
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_OnlyUser_ListsUserPlusPlatform
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_UserAndSpace_ListsBothPartitionsPlusPlatform
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_UserEqualsSpace_DedupedInAlternation
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildModelQueries_AllQueriesShareSameNodeTypeFilter
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildModelQueries_EmptySelection_EqualsDefault
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildModelQueries_NoSelection_IncludesRootCatalogOnly
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildModelQueries_NoUserPath_OmitsUserMemexQuery
…
MeshWeaver.AI.Test.AgentPickerModelOrderingTest ‑ APinnedModel_StaysInsideItsProvidersContiguousBlock
MeshWeaver.AI.Test.AgentPickerModelOrderingTest ‑ ProvidersWithNaturallyInterleavedOrders_StillRenderOneHeaderEach
MeshWeaver.AI.Test.AgentPickerModelOrderingTest ‑ TheRouter_LeadsEveryConcreteProvider_RegardlessOfAlphabeticalPosition
MeshWeaver.AI.Test.AgentPickerQueryTest ‑ AgentPickerQuery_KeepsConversational_ExcludesUtility_AssistantFirst
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Agent_WhoseContentIsTheAsWrittenDom_StillProjects
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Agent_WithJsonElementContent_StillProjects
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Agent_WithTypedContent_StillProjects
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Model_WhoseContentIsTheAsWrittenDom_StillProjects
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Node_WhoseContentIsNotAnAgent_StillProjectsToNull
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Skill_WhoseContentIsTheAsWrittenDom_StillProjects
…

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

593 tests  ±0   589 ✅ ±0   13m 9s ⏱️ - 1m 24s
  7 suites ±0     4 💤 ±0 
  7 files   ±0     0 ❌ ±0 

Results for commit 1fe2e3c. ± Comparison against base commit d9b59b6.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

    9 files  ±0      9 suites  ±0   7m 15s ⏱️ +8s
1 611 tests ±0  1 610 ✅ ±0  1 💤 ±0  0 ❌ ±0 
1 612 runs  ±0  1 611 ✅ ±0  1 💤 ±0  0 ❌ ±0 

Results for commit 1fe2e3c. ± Comparison against base commit d9b59b6.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

2 048 tests  ±0   1 855 ✅ ±0   8m 4s ⏱️ -17s
    9 suites ±0     193 💤 ±0 
    9 files   ±0       0 ❌ ±0 

Results for commit 1fe2e3c. ± Comparison against base commit d9b59b6.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

2 832 tests  ±0   2 729 ✅ ±0   9m 9s ⏱️ +2s
    9 suites ±0     103 💤 ±0 
    9 files   ±0       0 ❌ ±0 

Results for commit 1fe2e3c. ± Comparison against base commit d9b59b6.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

2 077 tests   - 19   2 073 ✅  - 22   14m 33s ⏱️ + 2m 1s
   10 suites ± 0       4 💤 + 3 
   10 files   ± 0       0 ❌ ± 0 

Results for commit 1fe2e3c. ± Comparison against base commit d9b59b6.

This pull request removes 670 and adds 651 tests. Note that renamed tests count towards both.
MeshWeaver.AI.Test.AgentPickerQueryTest ‑ AgentPickerQuery_KeepsConversational_ExcludesUtility_AssistantFirst
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Agent_WhoseContentIsTheAsWrittenDom_StillProjects
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Agent_WithJsonElementContent_StillProjects
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Agent_WithTypedContent_StillProjects
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Model_WhoseContentIsTheAsWrittenDom_StillProjects
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Node_WhoseContentIsNotAnAgent_StillProjectsToNull
MeshWeaver.AI.Test.AgentRosterContentShapeTest ‑ Skill_WhoseContentIsTheAsWrittenDom_StillProjects
MeshWeaver.AI.Test.AgentSelectionMatchedButUnbuildableTest ‑ MatchedAgent_WhoseCreationFails_SurfacesTheCreationFailure_NotAgentNotFound
MeshWeaver.AI.Test.AgentSelectionPathResolutionTest ‑ SelectAgent_WithEmptyCatalog_ReportsEmptyCatalog_NotStaleSelection
MeshWeaver.AI.Test.AgentSelectionPathResolutionTest ‑ SelectSpaceScopedAgent_ByFullPath_ResolvesThatAgent_NotTheCollidingBuiltIn
…
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_ExcludeUtility_AppendsUtilityFilter
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_NeitherSet_PlatformDefaultsOnly
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_OnlySpace_ListsSpacePlusPlatform
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_OnlyUser_ListsUserPlusPlatform
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_UserAndSpace_ListsBothPartitionsPlusPlatform
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildAgentQuery_UserEqualsSpace_DedupedInAlternation
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildModelQueries_AllQueriesShareSameNodeTypeFilter
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildModelQueries_EmptySelection_EqualsDefault
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildModelQueries_NoSelection_IncludesRootCatalogOnly
MeshWeaver.AI.Test.AgentPickerQueriesTest ‑ BuildModelQueries_NoUserPath_OmitsUserMemexQuery
…

@github-actions

Copy link
Copy Markdown
Contributor

Test Results

    53 files  ±0      53 suites  ±0   57m 21s ⏱️ -38s
11 178 tests +3  10 873 ✅ +3  305 💤 ±0  0 ❌ ±0 
11 732 runs  +4  11 427 ✅ +4  305 💤 ±0  0 ❌ ±0 

Results for commit 1fe2e3c. ± Comparison against base commit d9b59b6.

@rbuergi
rbuergi merged commit c2f4917 into main Aug 26, 2026
26 checks passed
@rbuergi
rbuergi deleted the fix/2331-model-picker-provider-order branch August 28, 2026 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A per-model Order pin splits its provider's block in the model picker — one provider, two headers

2 participants