From 992a965cd9152f76cd927c396ff888b89850780f Mon Sep 17 00:00:00 2001 From: chenchen Date: Thu, 7 May 2026 15:03:40 +0800 Subject: [PATCH] fix(agnet): preserve root admin's group during Agnet session sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit syncLocalUserFromAgnet rewrites users.group with the channelId returned by Agnet's /me on every web /sign-in. That's correct for normal users — their channel membership is owned by the Agnet identity service. But platform administrators (RoleRootUser) are provisioned out-of-band: operators set their group to "default" (or whichever billing tier) manually, and their NewAPI abilities exist there. When a root admin logs in via the web, Agnet returns a stub channelId that has no abilities rows. The current code overwrites users.group with that stub, and the next /v1/models call returns an empty list — the desktop client then falls back to providerPresets.defaultModels, hiding the real model catalogue from the operator. Add a role guard so the rewrite only fires for users below root. Root admins keep whatever group an operator set in the DB. Co-Authored-By: Claude Opus 4.7 (1M context) --- heicode/controller/heicode_agnet_session.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/heicode/controller/heicode_agnet_session.go b/heicode/controller/heicode_agnet_session.go index 534cd37..fdf1582 100644 --- a/heicode/controller/heicode_agnet_session.go +++ b/heicode/controller/heicode_agnet_session.go @@ -226,7 +226,13 @@ func syncLocalUserFromAgnet(me agnetMeEnvelope) (*model.User, error) { user.DisplayName = name changed = true } - if ch := strings.TrimSpace(me.Data.ChannelID); ch != "" && user.Group != ch { + // Platform administrators keep their human-assigned group (e.g. "default") + // regardless of what Agnet's /me returns. Operators provision channel + // membership for them manually; letting Agnet rewrite it on every web + // login would force them onto whatever stub channel Agnet hands out, and + // abilities lookup against that empty group would erase model visibility. + if ch := strings.TrimSpace(me.Data.ChannelID); ch != "" && user.Group != ch && + user.Role < common.RoleRootUser { user.Group = ch changed = true }