Skip to content

feat(ai): provider and OAuth parity for /login#193

Open
islee23520 wants to merge 18 commits into
code-yeongyu:mainfrom
islee23520:feat/auth-provider-parity
Open

feat(ai): provider and OAuth parity for /login#193
islee23520 wants to merge 18 commits into
code-yeongyu:mainfrom
islee23520:feat/auth-provider-parity

Conversation

@islee23520

@islee23520 islee23520 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds 18 API-key providers + OAuth flows (cursor, gitlab-duo, glm-zcode, google-antigravity, google-gemini-cli, kilo, kimi-code, openai-codex-device, perplexity, xai) and the remaining Gajae provider-ID gaps for full /login parity. packages/ai only, plus the coding-agent provider wiring (model-resolver, provider-display-names, auth-providers) that is exhaustive over the ai KnownProvider union.

Stack

Base unit of the auth split. The credential-broker and auth-gateway PRs stack on top of this branch.

Evidence

  • npm run check green (biome, tsgo, shrinkwrap, install-lock, neo).
  • ai parity tests pass (api-key-provider-parity, gajae-provider-id-gaps, oauth suites).
  • Source of truth: packages/ai/src/env-api-keys.ts; parity enforced by test/api-key-provider-parity.test.ts.

Note: the only pre-existing ai test failures are Cloudflare live-E2E tests that fail identically on main (live CF endpoint errors in this environment) — unrelated to this PR.

Note

This PR now also includes the synchronized environment-surface wiring (.devcontainer/devcontainer.json secrets, scripts/devenv-setup.mjs PROVIDER_KEYS, env-vars.md) — per the repo contract, those surfaces must track env-api-keys.ts, so they travel with the providers.

Add 18 API-key providers (alibaba-coding-plan, cursor, deepinfra, firepass,
fugu, gitlab-duo, glm-zcode, kagi, kilo, kimi-code, litellm, lm-studio,
minimax-code(-cn), moonshot, nanogpt, ollama(-cloud), openai-codex-device,
parallel, perplexity, qianfan, qwen-portal, synthetic, tavily, venice, vllm,
zenmux) plus OAuth flows for cursor, gitlab-duo, glm-zcode, google-antigravity,
google-gemini-cli, kilo, kimi-code, openai-codex-device, perplexity, xai, and
the remaining Gajae provider-ID gaps for full /login parity.

The coding-agent provider wiring (model-resolver defaults, provider-display-names,
auth-providers oauth-only set) travels here because model-resolver is exhaustive
over the ai KnownProvider union. Source of truth for keys remains env-api-keys.ts;
parity is enforced by test/api-key-provider-parity.test.ts.
Declare the API-key providers added for /login parity (alibaba-coding-plan,
deepinfra, firepass, fugu, kagi, litellm, lm-studio, nanogpt, ollama,
ollama-cloud, parallel, qianfan, qwen-portal, synthetic, tavily, venice,
vllm, zenmux) across the three synchronized environment surfaces:
.devcontainer/devcontainer.json secrets, scripts/devenv-setup.mjs PROVIDER_KEYS,
and .agents/skills/senpi-qa/references/env-vars.md. Source of truth remains
packages/ai/src/env-api-keys.ts.
- Remove kagi, parallel, and tavily providers (search-only, no chat)
- Fix GLM ZCode OAuth to pin endpoints to z.ai
- Add CRLF-delimited SSE parsing for provider streams
- Add GitLab Duo and Perplexity OAuth test coverage
- Update model-registry and model-resolver for removed providers
Resolve changes.md conflicts in packages/ai and packages/coding-agent
by keeping both the provider parity sections and the upstream sections.
Resolve provider-union conflicts with main Radius support while keeping
parity providers. Drop residual kagi/tavily/parallel env-surface wiring.
@islee23520

islee23520 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

@code-yeongyu This PR's CI is blocked before any jobs start: the fork workflow run concluded action_required, so the required Check and test context remains “Expected — Waiting for status to be reported.”

Could you open the run below and choose Approve and run workflows?

https://github.com/code-yeongyu/senpi/actions/runs/29494372152

No branch-protection or workflow change is requested; this only approves the existing run for this PR head SHA.

@code-yeongyu code-yeongyu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Review verdict: NEEDS-CHANGES

Thanks — the provider/OAuth surface is broad and most of the pure OAuth flow logic, env-key mappings, and tests are solid (mocked fetch, no real creds, no token spend; models.generated.ts is generator-consistent). But several advertised login paths cannot produce a working model request yet, and main has since restructured packages/ai (utils/oauth/auth/oauth/, provider factories, typed load.ts + bun-oauth.ts bundled loaders) and independently landed xAI device OAuth — so this needs a re-port, not a mechanical rebase.

Findings

Pri Location Finding
P1 packages/ai/src/providers/cursor.ts:17 Use Cursor's Connect transport instead of OpenAI completions — The new cursor/default catalog is declared as openai-completions, and cursorProvider() dispatches it through the generic OpenAI adapter. Cursor's provider contract uses its HTTP/2 Connect/protobuf AgentRun RPC rather than an OpenAI /chat/completions endpoint, so login can succeed but every subsequent Cursor model request is sent with the wrong protocol and fails.
P1 packages/ai/src/utils/oauth/perplexity.ts:205 Separate Perplexity session OAuth from direct API-key auth — The OTP/native-app flow returns a www.perplexity.ai web-session JWT, but this provider exposes that JWT through getApiKey() and the model provider sends it to https://api.perplexity.ai via the generic OpenAI adapter (packages/ai/src/providers/perplexity.ts:11-17). Perplexity session tokens are not direct API keys and are rejected by that endpoint, so the advertised OAuth path fails on its first model request.
P1 packages/ai/src/providers/gitlab-duo.ts:12 Exchange GitLab PAT credentials before proxy requests — The provider advertises GITLAB_TOKEN as an ordinary API key, but only OAuth credentials pass through getGitLabDuoDirectAccess(). Stored or environment API-key credentials therefore reach the GitLab AI proxy as the raw PAT and omit the short-lived direct-access token and instance headers that this patch itself obtains in packages/ai/src/utils/oauth/gitlab-duo.ts:96-131.
P1 packages/ai/src/providers/gitlab-duo.models.ts:21 Route GitLab GPT-5.1 through chat completions — This catalog marks gpt-5.1-2025-11-13 as openai-responses, so the provider posts a Responses payload to the GitLab OpenAI proxy. The GitLab Duo mapping for this model is the chat-completions API; only Codex-family mappings use Responses.
P1 packages/ai/src/utils/oauth/glm-zcode.ts:493 Preserve GLM bearer auth in the compatibility provider — glmZcodeOAuth.toAuth() returns both the provisioned key and Authorization: Bearer …, but the compatibility OAuthProviderInterface below exposes only getApiKey. The new coding-agent request-auth dispatcher falls back to that method when getRequestAuth is absent, so it drops the bearer header and the Anthropic adapter sends the key as X-Api-Key instead; stored GLM OAuth credentials cannot authenticate model calls.
P2 packages/coding-agent/src/core/auth-providers.ts:17 Exclude OAuth-only Google providers from API-key login — The new exclusion set contains only openai-codex-device, while BUILT_IN_PROVIDER_DISPLAY_NAMES now includes google-gemini-cli and google-antigravity. Because display-name presence unconditionally makes a provider API-key eligible, /login advertises API-key input for both providers even though their definitions expose only OAuth and their runtime requires serialized { token, projectId } credentials.

Merge path

  1. Re-port flows into packages/ai/src/auth/oauth/ against auth/types.ts (OAuthAuth/AuthInteraction), extend OAuthFlowLoaders in auth/oauth/load.ts, and register static imports in src/bun-oauth.ts.
  2. Drop the PR's xAI OAuth + provider changes entirely — main already has them (5220aba61, a01baaaea).
  3. Reconcile kimi-code with main's existing kimi-coding (same product, same KIMI_API_KEY, different API flavor) — one login entry, explicit decision.
  4. Fix the P1s above before re-advertising Cursor/Perplexity/GitLab/GLM in /login.
  5. GLM zcode flow: add PKCE (custom-scheme code interception risk) or document acceptance; Perplexity desktop-session borrow should be opt-in with user-facing consent.

FYI the Check and test failure on your last run was the flaky TestAttachOrSpawn_RaceExactlyOneDaemon Go test (it also flakes on main); I rerailed it and approved the pending workflow runs.

(Reviewed with the PR refs fetched locally against origin/main; line numbers refer to the PR head.)

… P1s, drop GLM ZCode

Re-port OAuth flows from utils/oauth to auth/oauth with bundledLoaders,
route Cursor through Connect/protobuf ChatService, fix GitLab PAT exchange
and gpt-5.1 chat-completions routing, delist Perplexity session OAuth from
/login, exclude Google CCA providers from API-key login, remove unofficial
GLM ZCode login, keep browser smoke Node-free, and update stale kimi-coding
live-test model ids.
@islee23520

Copy link
Copy Markdown
Contributor Author

Review follow-up status

Provider/OAuth parity review fixes were pushed earlier on this branch:

  • commit: eda7aba9c — re-port OAuth to auth/oauth, Cursor Connect transport, GitLab PAT exchange + gpt-5.1 chat-completions, Perplexity OAuth delisted, Google CCA API-key exclusion, GLM ZCode removed, browser-smoke Node-free.

Downstream stack also updated:

Bring PR code-yeongyu#193 onto current main auth/ModelRuntime layout while preserving
provider OAuth parity review fixes (Cursor Connect, GitLab, Perplexity
delist, Google OAuth-only, GLM ZCode removed) and regenerating model catalogs.
@gitguardian

gitguardian Bot commented Jul 18, 2026

Copy link
Copy Markdown

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

islee23520 added a commit to islee23520/senpi that referenced this pull request Jul 18, 2026
… main rebase

Rebase the broker branch onto the conflict-resolved code-yeongyu#193/main auth stack,
re-port multi-account vault hooks onto CredentialStore AuthStorage, and keep
broker review P1/P2 fixes (CAS disable, extras, lease prune, getRequestAuth).
islee23520 added a commit to islee23520/senpi that referenced this pull request Jul 18, 2026
…in rebase

Bring the gateway branch onto the conflict-resolved code-yeongyu#193/code-yeongyu#194 stack and keep
auth-gateway review P1/P2 fixes (broker URL validation, CORS preflight order,
verifier evidence, 502 mapping, qualified models).
@islee23520

Copy link
Copy Markdown
Contributor Author

Conflict resolution vs main

Merged origin/main into feat/auth-provider-parity and pushed.

  • Merge commit: e5c5e… (see latest HEAD on branch)
  • Strategy: keep main’s current auth/CredentialStore/ModelRuntime layout; preserve this PR’s review fixes (Cursor Connect, GitLab, Perplexity delist, Google OAuth-only, GLM ZCode removed, OAuth re-port under auth/oauth).
  • tsgo --noEmit clean after resolution.

Please re-check mergeability / CI on the updated head.

…er-parity

PR base is upstream main (not the fork). Merge upstream main and keep
provider/OAuth parity review fixes while accepting upstream model catalogs.
Drop the PR's xAI browser OAuth in favor of main's device-code flow, restore
OAuth-only API-key login exclusions for Google CCA providers, and keep the
provider/OAuth parity work on current main.
Keep main's device-code xAI flow (drop PR browser discovery), add a thin
legacy OAuthProviderInterface adapter for the compat registry, and exclude
google-gemini-cli / google-antigravity from API-key /login.
@islee23520

Copy link
Copy Markdown
Contributor Author

Babysit update (merge + review fixes)

Done this cycle

  1. Merged origin/main into feat/auth-provider-parity (branch was CONFLICTING). Conflicts were only in packages/ai/src/changes.md and packages/coding-agent/src/core/changes.md; both sides kept with correct section headers.
  2. Dropped PR xAI browser OAuth in favor of main’s device-code flow (packages/ai/src/auth/oauth/xai.ts + tests identical to main for the device grant path). Added a thin xaiOAuthProvider legacy adapter so the compat registry in auth/oauth/index.ts still has a defined id (avoids provider.id crashes when enumerating).
  3. Re-applied P2 Google OAuth-only login exclusion in packages/coding-agent/src/core/auth-providers.ts:
    • OAUTH_ONLY_MODEL_PROVIDERS = openai-codex-device | google-gemini-cli | google-antigravity
    • Checked before display-name API-key eligibility so /login no longer advertises API-key for CCA providers.

Already present on branch (prior eda7aba9c re-port — verified still true after merge)

Review P1 Status
Cursor Connect transport (not openai-completions) OK — cursorProvider() uses cursorConnectApi()
Perplexity session OAuth separated from API-key path OK — provider is API-key only; session flow not in getOAuthProviders() registry; tests assert no OAuth on model provider
GitLab PAT → getGitLabDuoDirectAccess for API-key creds OK — gitlabDuoApiKeyAuth().resolve exchanges PAT
GitLab GPT-5.1 → openai-completions OK — catalog type is openai-completions
GLM zcode bearer / getRequestAuth N/A — GLM ZCode deliberately dropped from PR
Re-port into auth/oauth + load.ts + bun-oauth.ts OK — flows live under packages/ai/src/auth/oauth/ with bundled loaders

Verification

  • cd packages/ai && npx vitest --run test/xai-oauth.test.ts14/14 pass (main device flow)
  • Also green: perplexity-oauth, gitlab-duo-oauth, gitlab-duo-models, cursor-connect (25 tests total in that batch)
  • biome check on touched xAI + auth-providers files clean
  • PR mergeable is now MERGEABLE (was CONFLICTING)

Remaining (not fully closed this cycle — still under CHANGES_REQUESTED)

  1. kimi-code vs main kimi-coding reconciliation — both remain registered (KIMI_API_KEY shared, different API flavors: OpenAI completions vs Anthropic messages). Review asked for one login entry / explicit product decision; not collapsed yet.
  2. Perplexity desktop-session borrow consent / opt-in UX and GLM zcode PKCE notes from review remain product/docs decisions (GLM path removed; Perplexity session flow is preserved but not advertised on the model provider).
  3. Full-repo npm run check not run this cycle (scoped tests + biome only). CI will re-run on the pushed head.

Pushed: a00dc64d3 on islee23520/senpi:feat/auth-provider-parity.

builtinProviders listed googleProvider() twice, so Models.setProvider
collapsed to 63 unique providers while the array length was 64 and
providers.test failed. Matches main's single registration.
@islee23520

Copy link
Copy Markdown
Contributor Author

Evidence-based follow-up (CI green path)

Review findings verification

Finding Verdict Evidence
Cursor Connect transport Already fixed on branch cursor.ts uses cursorConnectApi()
Perplexity session ≠ API key Already fixed session comments + separate path in perplexity.ts / oauth
GitLab PAT → direct access Already fixed getGitLabDuoDirectAccess on env token path
GitLab GPT-5.1 completions Already fixed model typed openai-completions
GLM bearer N/A on branch GLM zcode flow not present after re-port
Google OAuth-only login Already fixed OAUTH_ONLY_MODEL_PROVIDERS includes gemini-cli + antigravity
Drop PR xAI for main device Fixed earlier + verified auth/oauth/xai.ts is device-code; tests pass
kimi-code vs kimi-coding Open product decision both still registered; needs explicit single-login choice

CI root cause (this push)

builtinProviders() called googleProvider() twicesetProvider overwrote → getProviders().length === 63 while builtinProviders().length === 64.

Tests run locally (this cycle)

  • packages/ai: providers.test.ts, xai-oauth.test.ts, perplexity-oauth.test.ts, kilo-oauth.test.ts, api-key-provider-parity.test.ts41/41 pass
  • biome on touched files → clean

Not merging until Check and test is green and review is re-approved.

Expose minimax-code, minimax-code-cn, moonshot, and opencode-zen as
API-key login targets via display-name eligibility.
@islee23520

Copy link
Copy Markdown
Contributor Author

Evidence cycle 2

Added missing /login display names for minimax-code, minimax-code-cn, moonshot, and opencode-zen so API-key eligibility matches the Gajae parity intent on the provider-parity branch.

Local: ai provider/oauth suite 41/41, senpi-qa cli-smoke + mock-loop + rpc self-tests pass (local-ignore/qa-evidence/20260719-auth-pr193-evidence).

Open product item remains: kimi-code vs kimi-coding single login entry.

Not merging until green CI + re-review.

…render

Long absolute worktree paths wrap at render width 120, so compact
collapsed text is no longer a single line. Flatten whitespace before
asserting the compact resource label.
Build harness under real timers and enable fake timers only for the
idle-unload countdown so Vitest no longer flakes with 30s hangs on
advanceTimersByTimeAsync/runOnlyPendingTimersAsync in CI.
@islee23520

Copy link
Copy Markdown
Contributor Author

CI fix: app-server idle-unload timer flake

Root cause

Check and test was flaking on:

  • app-server-thread-handlers-catch.test.ts — idle unload registry error
  • app-server-thread-handlers-cold.test.ts — idle unload / transport-close / dispose timer cases

Those tests called vi.useFakeTimers() before async harness setup (createHarness / thread/start). Under load, Vitest fake timers could hang advanceTimersByTimeAsync / runOnlyPendingTimersAsync until the 30s suite timeout.

Fix (head a48f7d5819)

  • Build harness under real timers
  • Enable fake timers only for the idle-unload countdown (toFake: ["setTimeout","clearTimeout"])
  • Prefer advanceTimersByTimeAsync(0) for the zero-delay unload case

Local evidence

  • Targeted suite: 25/25 stress passes on main deps; 5/5 per PR worktree
  • Full packages/coding-agent vitest with the fix: 3781 passed | 31 skipped (432 files)
  • Pre-commit npm run check green on commit (PR feat(ai): provider and OAuth parity for /login #193 worktree)

Still open / not claimed closed

Please re-run review after CI is green on this head.

kimi-code and kimi-coding are the same product at api.kimi.com/coding with
the same KIMI_API_KEY. Upstream kimi-coding is the maintained entry
(k3 video input, adaptive thinking), so drop the PR-only kimi-code OAuth
provider and its catalog so /login shows exactly one Kimi entry.
Adds a regression asserting a single kimi-* provider and KIMI_API_KEY
resolution.
@islee23520

Copy link
Copy Markdown
Contributor Author

kimi-code vs kimi-coding — decision applied

Decision: keep upstream kimi-coding as the single Kimi /login entry. Rationale: both are the same product at api.kimi.com/coding with the same KIMI_API_KEY, and upstream kimi-coding is the actively maintained entry (k3 video input, adaptive thinking, generated model data). The PR-only kimi-code OAuth provider duplicated it.

What changed (head 5a55d911c)

  • Removed kimi-code OAuth provider, its catalog, generated data, and OAuth test
  • Removed all registrations (oauth index, providers/all, env map, model resolver, display names)
  • /login now shows exactly one Kimi entry: kimi-coding (API key, as upstream)
  • Added regression asserting a single kimi-* provider and KIMI_API_KEY resolution

Evidence

  • Focused regression: 2/2 pass (rerun independently after review)
  • packages/ai focused suite: 27/27 pass
  • npm run check: pass (biome 1843 files, tsgo, shrinkwrap/install locks, browser smoke, web-ui, neo build/vet/tests)
  • Real isolated CLI smoke: help/version/1,192-model listing/invalid-flag all correct, auth unchanged

Ready for re-review.

@islee23520

Copy link
Copy Markdown
Contributor Author

@code-yeongyu The kimi-code vs kimi-coding review item is now resolved per the decision above (single kimi-coding entry, upstream variant kept). CI is re-running on 5a55d911c. Could you re-review when you have a chance?

…parity

# Conflicts:
#	packages/ai/src/providers/data/openrouter.json
…parity

# Conflicts:
#	packages/ai/test/abort.test.ts
#	packages/ai/test/context-overflow.test.ts
#	packages/ai/test/cross-provider-handoff.test.ts
#	packages/ai/test/empty.test.ts
#	packages/ai/test/image-tool-result.test.ts
#	packages/ai/test/stream.test.ts
#	packages/ai/test/tokens.test.ts
#	packages/ai/test/tool-call-without-result.test.ts
#	packages/ai/test/total-tokens.test.ts
#	packages/ai/test/unicode-surrogate.test.ts
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.

2 participants