You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a first-class GitHub Copilot channel, separate from the existing Codex/ChatGPT OAuth channel. The implementation stays focused on the verified official Copilot API paths.
Evidence and design
Uses ChannelTypeCopilot = 112; moves Dummy to 113.
The relay always targets the official https://api.githubcopilot.com host: OpenAI Chat Completions uses /chat/completions; native Anthropic Claude uses /v1/messages.
GitHub Device Flow returns a gho_ OAuth App credential, forwarded directly as the upstream Bearer credential. The obsolete /copilot_internal/v2/token exchange and short-token cache were removed.
Copilot request headers use User-Agent: opencode/0.4.2, Openai-Intent, X-GitHub-Api-Version, X-Initiator, and an individual X-Request-Id; native Claude calls also use SSE Accept and anthropic-version.
The Client ID is an administrator-configured copilot.client_id system setting. No environment-variable fallback and no third-party OAuth App Client ID are embedded.
Device Flow requires Redis: sessions are server-side, bound to admin/channel, claimed with Redis SETNX, re-read after claim, consumed before credential write, and persisted only while the target remains a Copilot channel.
Copilot supports exactly one OAuth credential. New channels are created empty, then authorized with Device Flow.
Scope
Go channel registration, direct OAuth relay adapter, native Claude response handling, Device Flow admin APIs, and credential safeguards.
Console system setting for Client ID, empty-credential create UX, Device Flow dialog, and all 8 i18n locales.
Focused regression tests and an updated persisted design record.
Validation
go test ./setting/system_setting ./service ./controller ./relay/channel/copilot -run "Test.*Copilot|TestConvertClaudeRequestUsesNativePassthrough" -count=1
go vet ./service ./controller ./relay/channel/copilot ./setting/system_setting
bun test src/features/channels/lib/channel-form.test.ts src/features/channels/constants.test.ts
bun run typecheck
bun run i18n:sync
git diff --check
Risk and rollout
Router deploy is required because this changes /v1 relay routing and upstream authentication. Deploy newapi-console as well for the Client ID setting and authorization controls. Configure an organization-owned or enterprise-approved GitHub OAuth App Client ID and Redis; validate Device Flow, Chat Completions, native Claude /v1/messages, streaming/non-streaming, and concurrent multi-node polling in staging with an entitled test account. newapi-web, Terraform, and Cloudflare are not affected.
Resolved: the Copilot credential write now happens before best-effort Device Flow session cleanup, so a cleanup failure cannot discard a successful authorization.
Resolved: the Device Flow session persists the Client ID used to start it; polling is not broken if an admin changes the setting mid-flow.
Resolved: native Claude uses text/event-stream only for streaming and application/json otherwise.
Resolved: create validation now uses data.type, removing the stale currentType closure.
Resolved: the Copilot default base URL is cleared when selecting another type.
Resolved: dialog start requests are invalidated on close, and temporary poll failures retry instead of ending the authorization.
Resolved: same-value channel-key updates no longer falsely return record-not-found.
The former copilot_token singleflight/cache-prefix comments apply to the earlier exchange-token design; that code was removed in b69d0bb when the channel switched to direct gho_ OAuth credentials, so those items are obsolete.
Validation: go test ./service ./relay/channel/copilot ./model -run "TestCopilot|TestSetupRequestHeaderUses|TestConvertClaudeRequestUsesNativePassthrough" -count=1, go vet ./service ./relay/channel/copilot ./model, targeted Bun tests, and TypeScript typecheck passed.
Follow-up for comment 5280546802 (commit 2f79a9f18):
Resolved: sessions created before the Client ID snapshot field now recover it from the current configured Client ID during polling. New sessions remain pinned to their starting Client ID.
Resolved: stale start-request failures now pass the same request-id/open guard before changing dialog state or displaying a toast.
Already addressed in 816c535: zero affected rows now re-check the id + channel type before reporting success, preserving the type/deletion guard while avoiding MySQL no-op false negatives.
Validation: go test ./service -run TestCopilotDeviceFlow -count=1, go vet ./service, and cd web/default && bun run typecheck.
copilotDeviceMemoryStore.Lock()
defer copilotDeviceMemoryStore.Unlock()
session, found := copilotDeviceMemoryStore.sessions[flowID]
if found && session.ExpiresAt <= time.Now().Unix() {
delete(copilotDeviceMemoryStore.sessions, flowID)
delete(copilotDeviceMemoryStore.claims, flowID)
found = false
}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
Add a first-class GitHub Copilot channel, separate from the existing Codex/ChatGPT OAuth channel. The implementation stays focused on the verified official Copilot API paths.
Evidence and design
ChannelTypeCopilot = 112; moves Dummy to113.https://api.githubcopilot.comhost: OpenAI Chat Completions uses/chat/completions; native Anthropic Claude uses/v1/messages.gho_OAuth App credential, forwarded directly as the upstream Bearer credential. The obsolete/copilot_internal/v2/tokenexchange and short-token cache were removed.User-Agent: opencode/0.4.2,Openai-Intent,X-GitHub-Api-Version,X-Initiator, and an individualX-Request-Id; native Claude calls also use SSE Accept andanthropic-version.copilot.client_idsystem setting. No environment-variable fallback and no third-party OAuth App Client ID are embedded.SETNX, re-read after claim, consumed before credential write, and persisted only while the target remains a Copilot channel.Scope
Validation
go test ./setting/system_setting ./service ./controller ./relay/channel/copilot -run "Test.*Copilot|TestConvertClaudeRequestUsesNativePassthrough" -count=1go vet ./service ./controller ./relay/channel/copilot ./setting/system_settingbun test src/features/channels/lib/channel-form.test.ts src/features/channels/constants.test.tsbun run typecheckbun run i18n:syncgit diff --checkRisk and rollout
Router deploy is required because this changes
/v1relay routing and upstream authentication. Deploynewapi-consoleas well for the Client ID setting and authorization controls. Configure an organization-owned or enterprise-approved GitHub OAuth App Client ID and Redis; validate Device Flow, Chat Completions, native Claude/v1/messages, streaming/non-streaming, and concurrent multi-node polling in staging with an entitled test account.newapi-web, Terraform, and Cloudflare are not affected.