Skip to content

fix: preserve OpenAI-compatible alias matching before canonical fallback#3747

Closed
ht1072 wants to merge 2 commits into
router-for-me:devfrom
ht1072:fix/openai-compat-alias-canonical-provider-key
Closed

fix: preserve OpenAI-compatible alias matching before canonical fallback#3747
ht1072 wants to merge 2 commits into
router-for-me:devfrom
ht1072:fix/openai-compat-alias-canonical-provider-key

Conversation

@ht1072

@ht1072 ht1072 commented Jun 7, 2026

Copy link
Copy Markdown

Summary

  • normalize executor provider keys consistently when registering and resolving executors
  • preserve exact route-model matching before falling back to canonical/selection keys
  • add a regression test for mixed-case provider identifiers with suffixed OpenAI-compatible aliases

Problem

OpenAI-compatible aliases that include a visible suffix such as (high) can be listed successfully, but fail during auth selection when the runtime checks support only against canonicalized model keys. If the registry stores the exact alias while selection strips the suffix first, the candidate auth can be filtered out before any upstream request is attempted.

Root cause

authSupportsRouteModel() checked canonicalized route keys before considering the exact route model string, while OpenAI-compatible registries can expose the exact alias string as the supported model id. In mixed provider-id casing scenarios, executor lookup also benefits from using the same normalization helper everywhere.

Fix

  • add executorProviderKey() and use it consistently for executor register/lookup/unregister and legacy picker paths
  • make authSupportsRouteModel() try the raw routeModel first, then fall back to canonical/selection keys
  • add regression coverage for Identifier() == "YT", auth provider yt, and route model YT-GPT-5.5(high)

Validation

go test ./sdk/cliproxy/auth -run 'TestManager(ExecutorReturnsRegisteredExecutor|MixedLegacyFindsExecutorWithCanonicalProviderKey|RegisterExecutorClosesReplacedExecutionSessions)$'
go build -o /tmp/cli-proxy-api-pr-verify ./cmd/server && rm -f /tmp/cli-proxy-api-pr-verify

@github-actions github-actions Bot changed the base branch from main to dev June 7, 2026 10:10
@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown

This pull request targeted main.

The base branch has been automatically changed to dev.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9f374aefb1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

return
}
provider := strings.TrimSpace(executor.Identifier())
provider := executorProviderKey(executor.Identifier())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize executor lookup in auto-refresh loop

Because executors are now stored only under the canonical lower-case key here, the auto-refresh path still misses them when it does manager.executors[auth.Provider] in sdk/cliproxy/auth/auto_refresh_loop.go:236. For auths whose provider is mixed/upper case (for example a custom/OpenAI-compatible provider registered as YT), due auto-refresh sees exec == nil and just reschedules, so expiring credentials are never refreshed. Use the same canonical key helper for that lookup as well.

Useful? React with 👍 / 👎.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a helper function executorProviderKey to canonicalize provider keys (by trimming whitespace and converting to lowercase) and refactors various methods in conductor.go to use this helper. It also adds a direct model support check in authSupportsRouteModel and includes a new unit test to verify that pickNextMixedLegacy correctly finds executors using canonical provider keys. The review feedback suggests adding defensive nil checks for the Manager instance in pickNextLegacy and pickNextMixedLegacy to prevent potential nil-pointer panics when accessing mutexes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +3167 to +3170
provider = executorProviderKey(provider)
if provider == "" {
return nil, nil, &Error{Code: "provider_not_found", Message: "no provider supplied"}
}

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.

medium

If the Manager instance m is nil, calling m.HomeEnabled() on line 3163 will return false safely, but the code will then proceed to line 3167 and eventually panic on m.mu.RLock() at line 3175. Adding a defensive nil check for m at the beginning of the legacy path prevents this potential panic.

Suggested change
provider = executorProviderKey(provider)
if provider == "" {
return nil, nil, &Error{Code: "provider_not_found", Message: "no provider supplied"}
}
if m == nil {
return nil, nil, &Error{Code: "manager_nil", Message: "manager is nil"}
}
provider = executorProviderKey(provider)
if provider == "" {
return nil, nil, &Error{Code: "provider_not_found", Message: "no provider supplied"}
}

pinnedAuthID := pinnedAuthIDFromMetadata(opts.Metadata)
disallowFreeAuth := disallowFreeAuthFromMetadata(opts.Metadata)

providerSet := make(map[string]struct{}, len(providers))

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.

medium

If the Manager instance m is nil, calling m.HomeEnabled() on line 3303 will return false safely, but the code will then proceed to line 3310 and eventually panic on m.mu.RLock() at line 3328. Adding a defensive nil check for m at the beginning of the legacy path prevents this potential panic.

	if m == nil {
		return nil, nil, "", &Error{Code: "manager_nil", Message: "manager is nil"}
	}
	providerSet := make(map[string]struct{}, len(providers))

@ht1072

ht1072 commented Jun 7, 2026

Copy link
Copy Markdown
Author

Thanks for the automated review feedback. I pushed a follow-up commit that:

  • canonicalizes the auto-refresh executor lookup using the shared provider-key helper
  • adds a regression test for mixed-case OpenAI-compatible provider keys in the auto-refresh path
  • adds defensive nil guards in the legacy picker paths

Validation:

  • go test ./sdk/cliproxy/auth -run 'TestAutoRefreshLoopUsesCanonicalProviderKeyForExecutorLookup|TestManagerMixedLegacyFindsExecutorWithCanonicalProviderKey' -count=1
  • go build -o /tmp/cli-proxy-api-pr3747 ./cmd/server

GitHub checks are green on the latest commit.

@ht1072

ht1072 commented Jun 23, 2026

Copy link
Copy Markdown
Author

Closing this PR rather than leaving a stale/conflicted branch open. The fix still looks directionally useful, but the branch is now diverged from dev and not mergeable; if still needed, it should be recut cleanly from current dev with the same focused regression coverage.

@ht1072 ht1072 closed this Jun 23, 2026
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.

1 participant