Installation
| Platform | Installer | Portable |
|---|---|---|
| Windows x64 | Setup.exe | .zip |
| Windows arm64 | Setup.exe | .zip |
| Linux x64 | .AppImage · .deb · .rpm | — |
| Linux arm64 | .AppImage · .deb · .rpm | — |
| macOS x64 (Intel) | .pkg | .zip |
| macOS arm64 (Apple Silicon) | .pkg | .zip |
Existing installations update automatically via Velopack.
Added
- Edit custom provider dialog (
ProviderCatalogService,MainWindowViewModel,ProvidersView.axaml,MainWindow.axaml,MainWindow.axaml.cs,Resources/Strings.resx): custom OpenAI-compatible providers now have a pencil Edit provider action that opens an in-place popup mirroring the Add dialog, pre-filled with the provider's current name, base URL and API key. Confirming saves the changes via the newUpdateCustomProviderAsync, which rewritesproxy-config.yamland rebuilds the provider list. The dialog supports click-outside/Escape to dismiss and Enter to save. - Quotio-style Model Fallback bridge (
FallbackConfiguration,FallbackProxyService,EngineService,ConfigService,FallbackViewModel,FallbackView.axaml,MainWindowViewModel,Resources/Strings*.resx): added virtual models that map to ordered provider/model chains and automatically retry the next entry when quota/exhaustion-style responses are returned (429, selected5xx, auth/quota bodies). When Fallback is enabled, CLIProxyAPI is started behind an internal port and a lightweight local bridge owns the public port; when disabled, CLIProxyAPI runs directly so existing traffic is unaffected. The bridge rewrites chat/completions model ids, caches successful routes, publishes virtual models through/v1/models, reports active route state (N/M provider model) back to the UI, and is fully localized across all fourteen supported languages. - Fallback management UI and Local Proxy status (
FallbackView.axaml,Controls.axaml,MainWindow.axaml,ConfigurationView.axaml,ProviderIconRegistry,Resources/Strings*.resx): added a polished Fallback page with Quotio-inspired cards, icon-only actions, provider logos, add-model/add-entry flyouts, minimum-one-entry enforcement, animated expand/collapse (collapsed by default), active-route badges, Quotio credit link, and tooltips. The sidebar now shows consistent clickable status cards for CLIProxyAPI, Perplexity and Local Proxy, each with a status dot and localized tooltip; CLIProxyAPI/Perplexity route to their Providers tabs while Local Proxy scrolls directly to its CLIProxyAPI settings section. The CLIProxyAPI settings page includes a Local Proxy summary card with Providers-style endpoint copy, split route-cache enable/duration controls (including an until-restart cache mode), and internal-port details when the bridge is active. Fallback chains can be reordered with up/down controls (hidden at the ends instead of disabled), cached routes can be reset per virtual model, and individual entries can be marked as the route to use now. Virtual model header actions were reorganized (reset · delete · enable toggle), icon buttons gained hover/press scale animations, the remove-entry button is hidden when only one entry remains, and the experimental badge was removed. Destructive trash icons are now consistently red across Fallback, Home, Logs and Providers. - OAuth login feedback toast for every entry point (
OAuthService,OAuthConnectResult/OAuthConnectStatus,ProviderCatalogService,MainWindowViewModel,ProvidersView.axaml.cs,MainWindow.axaml,Resources/Strings*.resx): the "Add account → OAuth login" dialog button previously calledConnectOAuthAsyncand discarded its result, so adding an account for a provider that already had one (Claude, Codex, …) ran the flow with no visible feedback.OAuthService.ConnectAsyncnow returns a structuredOAuthConnectResult(status + dynamic detail) instead of an English string, andMainWindowViewModel.ConnectOAuthAsynccentralizes the status toast so both the provider-card button and the add-account dialog surface it. NewOAuth_Status_*strings localized across all fourteen languages. - Headless sign-in URL fallback (
OAuthService,MainWindowViewModel,MainWindow.axaml,MainWindow.axaml.cs): when the login process stays alive, the captured stdout is scanned for anhttp(s)URL (ExtractAuthUrl) and surfaced in the toast as a dedicated accent-colored, monospace "endpoint"-style row with an icon-only copy button (Copy→Check), so environments where the binary cannot open a browser can still complete the flow. The toast stays open while a URL is shown. - Auto-dismiss on successful authentication (
OAuthTokenDetector.GetLatestTokenWriteUtc,ProviderCatalogService.LatestOAuthTokenWriteUtc,MainWindowViewModel): the OAuth status toast now closes itself once the awaited provider gains a new account or its token file is rewritten (re-authenticating an existing account), detected via the auth-dir watcher against a baseline captured when the flow started, with a synchronous post-show check covering fast re-auth.
Changed
- Custom provider edit persistence and model refresh (
ProviderCatalogService,MainWindowViewModel,ModelFetchService,MainWindow.axaml,ProviderCatalogServiceTests): editing custom OpenAI-compatible providers now writes the provider name to the proxy-supportedname:field (not the unsupporteddisplay-name), validates URL/API key with the same localized error toast as Add, labels the model-selection confirm button as Save changes while editing, and restarts CLIProxyAPI after provider/model edits so Available Models refresh deterministically once the edited provider's models are registered. - Fallback master switch governs the Local Proxy lifecycle (
EngineService,FallbackViewModel,Resources/Strings*.resx): the local proxy bridge is now started/stopped solely by the Enable Fallback toggle instead of the combinedHasActiveRoutes(enabled + at least one usable virtual model). Disabling fallback now always stops the proxy, and enabling it starts the proxy even when no virtual models are configured (traffic is forwarded transparently). Adding/removing virtual models no longer restarts the engine since the bridge reads its configuration live; the engine only restarts when the toggle itself changes. TheEnable Fallbackdescription was updated to explain this across all fourteen supported languages. - Monogram fallback for unknown/custom provider icons (
ProviderIconRegistry,FallbackViewModel,AvailableModelViewModel,ProviderViewModel,QuotaProviderViewModel,ModelFetchService,FallbackView.axaml,ProvidersView.axaml,QuotaProvidersView.axaml): providers without a known brand glyph previously rendered the generic OpenAI swirl over a flat gray box, which was misleading for custom providers (whose name is user-chosen and arbitrary, e.g.Ohjbsdfjh). Unknown providers now show a monogram (the first letter of the display name) over a stable accent colour derived from the name (FNV-1a hash into a fixed palette), so custom providers are no longer mislabeled as OpenAI and are visually distinguishable from one another.ProviderIconRegistrygainedIsKnown,Monogram,FallbackColorand aGetDisplayhelper that centralizes the icon-vs-monogram decision; known brands (OpenAI, Claude, Gemini, Kimi, Cursor, …) are unchanged. Applies consistently across the Fallback page (model picker, entry rows, active-route badge), the Providers tab (configured providers and the available-models list) and the Quota providers tab. A user-selectable icon/colour picker remains possible as future work on top of this.
Fixed
- Local Proxy sidebar card now scrolls to the section content (
ConfigurationView.axaml,ConfigurationView.axaml.cs): clicking the sidebar Local Proxy status card switched to the CLIProxyAPI configuration tab but the follow-up scroll usually failed — a single delayed jump to the scroll extent raced Avalonia layout while the just-shown CLIProxy panel was still measuring, so the offset was computed against a stale/clamped extent and left the view at the top. The scroll is now retried on a short timer until the Local Proxy section is laid out and thenBringIntoView()is called on the section card, so the card reliably comes into view. - Home momentarily showed hardcoded fallback prices instead of cached OpenRouter pricing (
OpenRouterContextService,MainWindowViewModel): on launch the dashboard seeded persisted usage events and computed cost figures (OnUsageEventsLoaded→Recompute) beforeWarmModelPricingAsynchad loaded the on-disk OpenRouter price JSON, so the first render briefly used the built-in fallback table.OpenRouterContextServicegained a synchronousSeedFromDisk()that loads the cachedopenrouter-models.jsoninto memory, andMainWindowViewModelnow calls it before the initial usage seed — so cost estimates use real OpenRouter pricing from the first compute and the hardcoded table is only a true fallback for models the JSON does not list. The backgroundWarmAsyncrefresh still re-fetches stale pricing from the network. - Model selection UI froze on "Select all" / search with large providers (
MainWindowViewModel,MainWindow.axaml): selecting all models (or, for the custom-provider dialog, typing in the search box) froze the UI when a provider exposed hundreds of models (e.g. OpenRouter with 339+). Toggling "Select all" setIsSelectedon every model, and each change fired the per-itemPropertyChangedhandler which re-evaluated LINQ over the whole list (and, in the agent config overlay's Manual mode, re-ranRefreshManualPreviewAsyncper model) — an O(n²) cascade. Bulk selection now suppresses the per-item handler and raises the aggregate state once (custom-provider dialog and agent config overlay). The custom-provider model list also switched from a non-virtualizingItemsControlinside aScrollViewerto a virtualizingListBox, so "Select all" and search are now smooth. - Theme/Language combos clipped their text (
ConfigurationView.axaml): the General → Theme and Language combo boxes were140pxwide, which truncated longer entries such as "System default". Both are now155pxso the full text fits. - Gray Fluent press background bleeding through all buttons (
Controls.axaml): clicking and holding (or click-dragging) almost any button briefly revealed the FluentTheme default:pressedgrayContentPresenterbackground, because the custom button styles only overrode:pointerover. Added matching:pressedstates for every affected control (Button.app/.primary,rail,icon,link,side/.selected,proxy-card,provider-row-name,link-add,tab-item/.active, and theToggleButton.provider-row/model-groupheaders) so each uses its own pressed color instead of the stray gray. - Off-center provider icons in the Fallback page (
FallbackView.axaml): the SimpleIcons glyphs (e.g. OpenAI) in the model-selection popup and virtual-model entry rows looked nudged up and to the left. The icon containers used odd icon/box size differences (an 11px icon in a 20px box → 4.5px margins, 13px in 26px → 6.5px margins), so layout rounding snapped the half-pixel and offset the glyph. The icon sizes are now12(popup) and14(entries), giving exact integer margins so every fallback icon centers precisely. ProvidersView was unaffected because it already uses even differences (14px in 28/30px boxes).
Changed
- OAuth quick-exit success detection by exit code (
OAuthService): a login process that exits within the startup window is now judged by its exit code instead of grepping stdout for"Opening browser"/"Attempting to open URL"literals (which break across binary releases). The exit code is captured inside theExitedhandler via aTaskCompletionSourceso callers never touch a disposedProcess, and the process is always disposed once it exits (a successful login keeps it alive until the user completes the flow). - Strip native PDBs from the Scoop zip (
.github/workflows/release.yml): the SkiaSharp NuGet packages shiplibSkiaSharp.pdb(~84 MB) andlibHarfBuzzSharp.pdb(~20 MB) in the publish output, andDebugType=Noneonly removes our own managed PDBs. These native symbols are now deleted fromartifacts/publish-scoopbefore zipping, so the Scoop zip contains justTunnelAgent.exe(no loose DLLs or PDBs) and is substantially smaller.