Skip to content

Add GitLab Duo provider support#428

Merged
luispater merged 8 commits intorouter-for-me:mainfrom
LuxVTZ:feat/gitlab-duo-auth-plus
Mar 11, 2026
Merged

Add GitLab Duo provider support#428
luispater merged 8 commits intorouter-for-me:mainfrom
LuxVTZ:feat/gitlab-duo-auth-plus

Conversation

@LuxVTZ
Copy link

@LuxVTZ LuxVTZ commented Mar 10, 2026

Summary

Port GitLab Duo support to CLIProxyAPIPlus after maintainer guidance that third-party provider work belongs in this repository.

This PR adds:

  • OAuth login for GitLab Duo
  • personal access token login for GitLab Duo
  • refresh of GitLab direct_access metadata and managed credentials
  • dynamic model discovery from GitLab metadata instead of a hardcoded model list
  • native GitLab AI gateway routing for Anthropic-managed Duo models
  • native GitLab AI gateway routing for OpenAI/Codex-managed Duo models
  • handler-level smoke coverage for Claude-compatible and OpenAI-compatible downstream APIs
  • English and Chinese GitLab Duo usage docs for the Plus repo

Transport behavior

GitLab Duo now routes by provider-aware transport instead of relying only on the GitLab text wrapper APIs:

  • Anthropic-managed models delegate through the GitLab AI gateway Anthropic proxy and the existing ClaudeExecutor
  • OpenAI/Codex-managed models delegate through the GitLab AI gateway OpenAI proxy and the existing CodexExecutor
  • /v1/messages, /v1/chat/completions, and /v1/responses are covered by smoke tests

Testing

Targeted GitLab Duo packages:

  • go test ./internal/auth/gitlab ./internal/runtime/executor ./sdk/api/handlers/claude ./sdk/api/handlers/openai ./sdk/auth ./sdk/cliproxy

Full suite note:

  • go test ./... currently fails on clean plus/main in internal/api/modules/amp
  • reproduced on detached plus/main with:
    • go test ./internal/api/modules/amp -run TestModifyResponse_GzipScenarios/skips_non_2xx_status -count=1

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly expands the CLIProxyAPI's capabilities by integrating GitLab Duo as a fully supported AI provider. The changes enable seamless authentication via OAuth or PAT, dynamic discovery of available models, and intelligent routing of requests through GitLab's AI gateway to the appropriate underlying model (Anthropic or OpenAI/Codex). This improves the user experience by offering a more native and flexible interaction with GitLab Duo's AI services, moving beyond simple text wrapping to a more deeply integrated and performant solution.

Highlights

  • GitLab Duo Provider Integration: Introduced comprehensive support for GitLab Duo as a first-class provider, enabling both OAuth and personal access token (PAT) login methods.
  • Dynamic Model Discovery and Routing: Implemented dynamic model discovery from GitLab's direct_access metadata, replacing hardcoded model lists. This includes native routing through the GitLab AI gateway for both Anthropic-managed and OpenAI/Codex-managed Duo models.
  • Enhanced API Compatibility: Added handler-level smoke tests to ensure compatibility with Claude-compatible (/v1/messages) and OpenAI-compatible (/v1/chat/completions, /v1/responses) downstream APIs when using GitLab Duo models.
  • Documentation and Planning: Provided new English and Chinese documentation for GitLab Duo usage and included a detailed plan for achieving full 'Codex parity' with GitLab Duo's capabilities.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • README.md
    • Updated the README to announce GitLab Duo support and link to new documentation.
  • README_CN.md
    • Updated the Chinese README to announce GitLab Duo support and link to new documentation.
  • cmd/server/main.go
    • Added new command-line flags for GitLab Duo OAuth and PAT login.
    • Integrated new login functions for GitLab Duo into the main command execution flow.
  • docs/gitlab-duo.md
    • Added new documentation detailing GitLab Duo integration, login methods, model usage, and current scope.
  • docs/gitlab-duo_CN.md
    • Added new Chinese documentation detailing GitLab Duo integration, login methods, model usage, and current scope.
  • gitlab-duo-codex-parity-plan.md
    • Added a new planning document outlining future work to achieve full 'Codex parity' for GitLab Duo, including detailed tasks and sprints.
  • internal/auth/gitlab/gitlab.go
    • Added core GitLab authentication logic, including OAuth flow, PKCE code generation, token exchange, and direct access metadata fetching.
    • Implemented utility functions for URL normalization, token expiry calculation, and discovered model extraction.
  • internal/auth/gitlab/gitlab_test.go
    • Added unit tests for GitLab authentication client, covering auth URL generation, token exchange, and model metadata extraction.
  • internal/cmd/auth_manager.go
    • Registered the new GitLab authenticator with the central authentication manager.
  • internal/cmd/gitlab_login.go
    • Added new command functions to handle GitLab Duo OAuth and PAT login processes, integrating with the SDK's authentication manager.
  • internal/runtime/executor/gitlab_executor.go
    • Implemented the GitLab Duo executor, handling request translation, native AI gateway routing for Anthropic and OpenAI models, and fallback to Code Suggestions API.
    • Included logic for refreshing OAuth tokens and merging direct access metadata.
    • Defined functions for building GitLab prompts, parsing responses, and handling streaming chunks.
  • internal/runtime/executor/gitlab_executor_test.go
    • Added unit tests for the GitLab Duo executor, verifying chat endpoint usage, fallback mechanisms, Anthropic and OpenAI gateway routing, and metadata refresh.
  • sdk/api/handlers/claude/gitlab_duo_handler_test.go
    • Added handler-level smoke tests for Claude-compatible API endpoints using GitLab Duo's Anthropic gateway integration.
  • sdk/api/handlers/openai/gitlab_duo_handler_test.go
    • Added handler-level smoke tests for OpenAI-compatible API endpoints (chat completions and responses) using GitLab Duo's OpenAI gateway integration.
  • sdk/auth/gitlab.go
    • Implemented the SDK-level GitLab authenticator, managing OAuth and PAT login flows, environment variable resolution, and user input prompts.
    • Included helper functions for sanitizing filenames and masking tokens.
  • sdk/auth/gitlab_test.go
    • Added unit tests for the GitLab authenticator, specifically verifying PAT login and metadata handling.
  • sdk/auth/refresh_registry.go
    • Registered the GitLab authenticator for automatic token refresh within the SDK.
  • sdk/cliproxy/auth/types.go
    • Updated the AccountInfo method to correctly identify and display account information for GitLab OAuth and PAT authentication methods.
  • sdk/cliproxy/service.go
    • Registered the new GitLab authenticator with the default authentication manager.
    • Ensured the GitLab executor is registered when a GitLab authentication is active.
    • Updated model registration logic to fetch and apply models from GitLab Duo authentication metadata.
  • sdk/cliproxy/service_gitlab_models_test.go
    • Added a test to verify that the service correctly registers GitLab Duo models, including the stable alias and dynamically discovered models.
Activity
  • The author, LuxVTZ, created this pull request to add GitLab Duo provider support.
  • The pull request description provides a detailed summary of the changes, transport behavior, and testing instructions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@LuxVTZ
Copy link
Author

LuxVTZ commented Mar 10, 2026

Thanks for the redirect. I ported the GitLab Duo work to CLIProxyAPIPlus and rebased it onto . The provider support, gateway routing, smoke tests, and docs are all included here now.\n\nValidation:\n- targeted GitLab Duo packages pass\n- full ? github.com/router-for-me/CLIProxyAPI/v6/cmd/server [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/examples/custom-provider [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/examples/http-request [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/examples/translator [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/access [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/access/config_access [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/api (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/api/handlers/management (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/api/middleware (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/api/modules [no test files]
time="2026-03-10T22:37:30+04:00" level=info msg="amp upstream proxy enabled for: http://127.0.0.1:46273"
time="2026-03-10T22:37:30+04:00" level=warning msg="amp module: no auth middleware provided, allowing all requests"
time="2026-03-10T22:37:30+04:00" level=info msg="amp upstream proxy enabled for: http://127.0.0.1:40773"
time="2026-03-10T22:37:30+04:00" level=info msg="amp upstream proxy enabled for: http://example.com"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 2 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 2 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=warning msg="amp model mapping: skipping invalid mapping (from="", to="model-b")"
time="2026-03-10T22:37:30+04:00" level=warning msg="amp model mapping: skipping invalid mapping (from="model-a", to="")"
time="2026-03-10T22:37:30+04:00" level=warning msg="amp model mapping: skipping invalid mapping (from="", to="model-b")"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 regex mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 regex mapping(s)"
time="2026-03-10T22:37:30+04:00" level=warning msg="amp model mapping: invalid regex "(": error parsing regexp: missing closing ): (?i)("
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 regex mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 regex mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=info msg="amp model mapping: loaded 1 mapping(s)"
time="2026-03-10T22:37:30+04:00" level=warning msg="amp proxy: gzip decompress error: unexpected EOF"
time="2026-03-10T22:37:30+04:00" level=warning msg="amp proxy: gzip header detected but decompress failed: unexpected EOF"
--- FAIL: TestModifyResponse_GzipScenarios (0.00s)
--- FAIL: TestModifyResponse_GzipScenarios/skips_non_2xx_status (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered, repanicked]
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x899db2]

goroutine 105 [running]:
testing.tRunner.func1.2({0x968a20, 0xebdb50})
/home/luxvtz/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.26.0.linux-amd64/src/testing/testing.go:1974 +0x232
testing.tRunner.func1()
/home/luxvtz/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.26.0.linux-amd64/src/testing/testing.go:1977 +0x349
panic({0x968a20?, 0xebdb50?})
/home/luxvtz/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.26.0.linux-amd64/src/runtime/panic.go:860 +0x13a
github.com/router-for-me/CLIProxyAPI/v6/internal/api/modules/amp.createReverseProxy.func2(0x1c429922900)
/home/luxvtz/projects/cliproxyapi/CLIProxyAPI/internal/api/modules/amp/proxy.go:117 +0x92
github.com/router-for-me/CLIProxyAPI/v6/internal/api/modules/amp.TestModifyResponse_GzipScenarios.func1(0x1c42995cfc8)
/home/luxvtz/projects/cliproxyapi/CLIProxyAPI/internal/api/modules/amp/proxy_test.go:144 +0x218
testing.tRunner(0x1c42995cfc8, 0x1c429c944d0)
/home/luxvtz/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.26.0.linux-amd64/src/testing/testing.go:2036 +0xea
created by testing.(*T).Run in goroutine 93
/home/luxvtz/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.26.0.linux-amd64/src/testing/testing.go:2101 +0x4c5
FAIL github.com/router-for-me/CLIProxyAPI/v6/internal/api/modules/amp 0.035s
? github.com/router-for-me/CLIProxyAPI/v6/internal/auth [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/auth/antigravity [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/auth/claude [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/auth/codex (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/auth/copilot (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/auth/empty [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/auth/gemini [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/auth/gitlab (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/auth/iflow [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/auth/kilo [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/auth/kimi [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/auth/kiro (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/auth/qwen [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/auth/vertex [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/browser [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/buildinfo [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/cache (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/cmd [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/config (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/constant [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/interfaces [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/logging (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/managementasset [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/misc [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/registry (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/runtime/executor (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/runtime/geminicli [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/store [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/thinking (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/antigravity [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/claude [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/codex [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/gemini [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/geminicli [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/iflow [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/kimi (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/openai [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/antigravity/claude (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/antigravity/gemini (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/antigravity/openai/chat-completions (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/antigravity/openai/responses [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/claude/gemini [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/claude/gemini-cli [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/claude/openai/chat-completions (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/claude/openai/responses [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/codex/claude [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/codex/gemini [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/codex/gemini-cli [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/codex/openai/chat-completions (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/codex/openai/responses (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/claude (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/gemini [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/gemini-cli [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/openai/chat-completions [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/openai/responses (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini-cli/claude (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini-cli/gemini [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini-cli/openai/chat-completions [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini-cli/openai/responses [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/kiro/claude [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/kiro/common (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/kiro/openai (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/translator/openai/claude (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/openai/gemini [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/openai/gemini-cli [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/openai/openai/chat-completions [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/openai/openai/responses [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/translator/translator [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/tui [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/internal/usage [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/internal/util (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/watcher (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/watcher/diff (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/internal/watcher/synthesizer (cached)
? github.com/router-for-me/CLIProxyAPI/v6/internal/wsrelay [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/sdk/access [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/sdk/api [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/claude (cached)
? github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/gemini [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers/openai (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/sdk/auth (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy (cached)
ok github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth (cached)
? github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/pipeline [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/usage [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/sdk/config [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/sdk/logging [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/sdk/translator [no test files]
? github.com/router-for-me/CLIProxyAPI/v6/sdk/translator/builtin [no test files]
ok github.com/router-for-me/CLIProxyAPI/v6/test (cached)
FAIL is still failing on clean in , so I called that out in the PR body as a baseline issue rather than a GitLab Duo regression

@LuxVTZ
Copy link
Author

LuxVTZ commented Mar 10, 2026

Thanks for the redirect. I ported the GitLab Duo work to CLIProxyAPIPlus and rebased it onto plus/main.

This PR now contains the provider support, gateway routing, smoke tests, and docs.

Validation:

  • targeted GitLab Duo packages pass
  • full go test ./... is still failing on clean plus/main in internal/api/modules/amp, so I called that out in the PR body as a baseline issue rather than a GitLab Duo regression

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

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 comprehensive GitLab Duo support to CLIProxyAPI, enabling OAuth and Personal Access Token (PAT) authentication, dynamic model discovery, and routing through GitLab's AI gateway for Anthropic and OpenAI models. The changes include new command-line flags for login, a dedicated authentication package, and an executor that handles request translation, streaming, and token refreshing, with fallback mechanisms. New documentation for setup and usage has also been added. Review comments suggest improving the streaming implementation to avoid a potentially degraded user experience when falling back to synthetic streaming, and recommend using more descriptive variable names for gitlabLogin and gitlabTokenLogin to enhance code clarity.

Note: Security Review did not run due to the size of the PR.

Comment on lines +125 to +127
} else if !shouldFallbackToCodeSuggestions(streamErr) {
return nil, streamErr
}

Choose a reason for hiding this comment

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

high

The code currently falls back to synthetic streaming if real streaming fails. However, the comment indicates that synthetic streaming is not good enough for codex parity. This could lead to a degraded user experience. Consider implementing a more robust streaming solution or explicitly declining the request if real streaming is unavailable.

Comment on lines +82 to +83
var gitlabLogin bool
var gitlabTokenLogin bool

Choose a reason for hiding this comment

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

medium

The variable names gitlabLogin and gitlabTokenLogin are very similar and could be easily confused. Consider using more descriptive names to improve clarity.

@luispater luispater merged commit df5595a into router-for-me:main Mar 11, 2026
2 checks passed
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