-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(providers): add Qwen Cloud individual token-plan provider #2361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 5 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
df23669
feat(providers): add Qwen Cloud individual token-plan provider
umutkeltek 27e2096
fix(qwen-cloud): require login ticket for session validation and norm…
umutkeltek d6a1184
test(qwen-cloud): add regression fixture for authenticated no-subscri…
umutkeltek 9085e05
Fix Qwen token plan usage windows
umutkeltek 008dc97
Fix Qwen Cloud usage request context
umutkeltek a3b8c9c
Allow browser cookie retry from provider settings
umutkeltek 6026fd0
Fix Qwen Cloud browser session requests
umutkeltek b24f2c2
refactor(providers): extract AlibabaCodingPlan cookie importer behind…
umutkeltek ec900eb
refactor(providers): extract OneConsole cookie-header pair from Aliba…
umutkeltek 467fb95
refactor(providers): consolidate OneConsole JSON traversal helpers
umutkeltek ec83b73
refactor(providers): consolidate OneConsole SEC token resolver
umutkeltek 434ac77
refactor(alibaba-coding-plan): consume shared OneConsole JSON helpers
umutkeltek 14d6f7c
refactor(alibaba-token-plan): consume shared OneConsole JSON helpers
umutkeltek bbe04c2
feat(providers): support per-host cookie routing on HTTP transport
umutkeltek 93f90c7
refactor(qwen-cloud): split fetcher into API client + parser + orches…
umutkeltek 8fa0752
test(qwen-cloud): switch to bundle-loaded fixture tests
umutkeltek 8bd28c1
docs(providers): document shared OneConsole infrastructure
umutkeltek 4ad0a25
Harden OneConsole shared refactor
umutkeltek b5f9b6c
Address Qwen review feedback
umutkeltek 529cc6c
Keep Qwen imports Chrome-only
umutkeltek 7d1d43d
Merge remote-tracking branch 'origin/main' into codex/pr-2361-repair
steipete 2b44b6b
Preserve SEC token network failures
umutkeltek f74cf1b
fix(one-console): restore legacy date parsing
steipete 498aef6
Merge commit '2b44b6b1cef09d0eaec12ca9c524f0427cb64065' into codex/pr…
steipete File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
91 changes: 91 additions & 0 deletions
91
Sources/CodexBar/Providers/QwenCloud/QwenCloudProviderImplementation.swift
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| import AppKit | ||
| import CodexBarCore | ||
| import Foundation | ||
| import SwiftUI | ||
|
|
||
| struct QwenCloudProviderImplementation: ProviderImplementation { | ||
| let id: UsageProvider = .qwencloud | ||
|
|
||
| @MainActor | ||
| func presentation(context _: ProviderPresentationContext) -> ProviderPresentation { | ||
| ProviderPresentation { context in | ||
| context.store.sourceLabel(for: context.provider) | ||
| } | ||
| } | ||
|
|
||
| @MainActor | ||
| func observeSettings(_ settings: SettingsStore) { | ||
| _ = settings.qwenCloudCookieSource | ||
| _ = settings.qwenCloudCookieHeader | ||
| } | ||
|
|
||
| @MainActor | ||
| func settingsSnapshot(context: ProviderSettingsSnapshotContext) -> ProviderSettingsSnapshotContribution? { | ||
| _ = context | ||
| return .qwenCloud(context.settings.qwenCloudSettingsSnapshot()) | ||
| } | ||
|
|
||
| @MainActor | ||
| func settingsPickers(context: ProviderSettingsContext) -> [ProviderSettingsPickerDescriptor] { | ||
| let cookieBinding = Binding( | ||
| get: { context.settings.qwenCloudCookieSource.rawValue }, | ||
| set: { raw in | ||
| context.settings.qwenCloudCookieSource = ProviderCookieSource(rawValue: raw) ?? .auto | ||
| }) | ||
| let cookieOptions = ProviderCookieSourceUI.options( | ||
| allowsOff: false, | ||
| keychainDisabled: context.settings.debugDisableKeychainAccess) | ||
| let cookieSubtitle: () -> String? = { | ||
| ProviderCookieSourceUI.subtitle( | ||
| source: context.settings.qwenCloudCookieSource, | ||
| keychainDisabled: context.settings.debugDisableKeychainAccess, | ||
| auto: "Automatic imports browser cookies from Qwen Cloud.", | ||
| manual: "Paste a Cookie header from home.qwencloud.com.", | ||
| off: "Qwen Cloud cookies are disabled.") | ||
| } | ||
|
|
||
| return [ | ||
| ProviderSettingsPickerDescriptor( | ||
| id: "qwen-cloud-cookie-source", | ||
| title: "Cookie source", | ||
| subtitle: "Automatic imports browser cookies from Qwen Cloud.", | ||
| dynamicSubtitle: cookieSubtitle, | ||
| binding: cookieBinding, | ||
| options: cookieOptions, | ||
| isVisible: nil, | ||
| onChange: nil, | ||
| trailingText: { | ||
| guard let entry = CookieHeaderCache.loadForDisplay(provider: .qwencloud) else { return nil } | ||
| let when = entry.storedAt.relativeDescription() | ||
| return "Cached: \(entry.sourceLabel) • \(when)" | ||
| }), | ||
| ] | ||
| } | ||
|
|
||
| @MainActor | ||
| func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] { | ||
| [ | ||
| ProviderSettingsFieldDescriptor( | ||
| id: "qwen-cloud-cookie", | ||
| title: "Cookie header", | ||
| subtitle: "", | ||
| kind: .secure, | ||
| placeholder: "Cookie: ...", | ||
| binding: context.stringBinding(\.qwenCloudCookieHeader), | ||
| actions: [ | ||
| ProviderSettingsActionDescriptor( | ||
| id: "qwen-cloud-open-dashboard", | ||
| title: "Open Token Plan", | ||
| style: .link, | ||
| isVisible: nil, | ||
| perform: { | ||
| NSWorkspace.shared.open(QwenCloudUsageFetcher.dashboardURL) | ||
| }), | ||
| ], | ||
| isVisible: { | ||
| context.settings.qwenCloudCookieSource == .manual | ||
| }, | ||
| onActivate: nil), | ||
| ] | ||
| } | ||
| } |
30 changes: 30 additions & 0 deletions
30
Sources/CodexBar/Providers/QwenCloud/QwenCloudSettingsStore.swift
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import CodexBarCore | ||
| import Foundation | ||
|
|
||
| extension SettingsStore { | ||
| var qwenCloudCookieHeader: String { | ||
| get { self.configSnapshot.providerConfig(for: .qwencloud)?.sanitizedCookieHeader ?? "" } | ||
| set { | ||
| self.updateProviderConfig(provider: .qwencloud) { entry in | ||
| entry.cookieHeader = self.normalizedConfigValue(newValue) | ||
| } | ||
| self.logSecretUpdate(provider: .qwencloud, field: "cookieHeader", value: newValue) | ||
| } | ||
| } | ||
|
|
||
| var qwenCloudCookieSource: ProviderCookieSource { | ||
| get { self.resolvedCookieSource(provider: .qwencloud, fallback: .auto) } | ||
| set { | ||
| self.updateProviderConfig(provider: .qwencloud) { entry in | ||
| entry.cookieSource = newValue | ||
| } | ||
| self.logProviderModeChange(provider: .qwencloud, field: "cookieSource", value: newValue.rawValue) | ||
| } | ||
| } | ||
|
|
||
| func qwenCloudSettingsSnapshot() -> ProviderSettingsSnapshot.QwenCloudProviderSettings { | ||
| ProviderSettingsSnapshot.QwenCloudProviderSettings( | ||
| cookieSource: self.qwenCloudCookieSource, | ||
| manualCookieHeader: self.qwenCloudCookieHeader) | ||
| } | ||
| } |
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| // Generated by Scripts/regenerate-codex-parser-hash.sh. Do not edit by hand. | ||
|
|
||
| enum CodexParserHash { | ||
| static let value = "48ac20dad61e9a7f" | ||
| static let value = "e8496ca631793ba0" | ||
| } |
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the generic importer falls back to the locked Chromium DB path, this call still uses
AlibabaChromiumCookieFallbackImporter.importSession, whose own private session check requires bothlogin_aliyunid_ticketand an Aliyun account cookie before it returns. For Qwen SSO profiles that only haveqwen_sso_ticket(accepted byQwenCloudCookieImport.authTicketCookies), the fallback returns nil before the provider-specific predicate below can accept it, so Auto import fails even though a valid Qwen session is present; pass the provider auth predicate into the fallback importer or return candidate cookies for the outer check.Useful? React with 👍 / 👎.