* feat(abacus): add Abacus AI provider with cookie-based usage fetching Add support for Abacus AI (ChatLLM/RouteLLM) as a new provider. Uses browser cookie authentication against the describeUser API endpoint to fetch compute point usage. Values are in centi-credits (divided by 100 for display). Primary window shows monthly credit usage as percentage, secondary window shows 7-day usage. Reset date derived from lastBilledAt + 1 month. * fix(abacus): fix usage display formatting and match Claude pattern - Fix credits format string (Swift String(format:) has no comma flag; use NumberFormatter for thousands separators) - Remove secondary weekly window (Abacus has monthly billing only) - Show credits detail below gauge (follow Warp/Kilo pattern for resetDescription rendering) - Add pace/reserve/deficit estimate on primary monthly window - Remove inactive status page URL (abacus.statuspage.io is inactive) - Hide account email/org from menu (not relevant for display) - Set windowMinutes to 30 days so pace calculation works correctly * feat(abacus): add pace tick and detail lines to card view - Show pace indicator tick (green/red) on the primary gauge bar - Add reserve/deficit line below gauge with pace right label - Show credits used/total as detail text below the gauge - Restore account identity (email, org, plan tier) in card header * fix(abacus): use correct API endpoints for credits and billing date Switch from describeUser (stale centi-credit values, no billing date) to _getOrganizationComputePoints (accurate credits in real units) and _getBillingInfo (exact nextBillingDate and subscription tier). Both endpoints are fetched concurrently. * fix(abacus): validate session cookies and preserve API errors Skip browser cookie sets that only contain anonymous/marketing cookies by checking for session/auth cookie names before accepting a set. This prevents using invalid cookies when a valid session exists in a later browser profile. Separate the cookie import and API fetch try blocks so that network, parse, or auth errors from the API are not misreported as "Browser cookie import failed" and incorrectly replaced with noSessionCookie. * fix(abacus): fix compilation after UsagePaceText API refactor Update three call sites that still used the removed UsagePaceText.weeklySummary(provider🪟) and weeklyPaceDetail(provider:window:now:showUsed:) signatures. MenuDescriptor and MenuCardView now use the store.weeklyPace()+ UsagePaceText.weeklySummary(pace:) pattern. StatusItemController computes weeklyPace from primary for Abacus (no secondary window). * fix(abacus): fix menu bar metric options and pace indicator Remove Secondary (Weekly) from the menu bar metric picker since Abacus has no secondary window; only Automatic and Primary (Credits) are valid options. Enable pace computation for Abacus in weeklyPace() so the bar tick indicator (reserve/deficit/on-pace) is rendered correctly. Abacus uses the simple UsagePace.weekly() path with the monthly window already set in RateWindow (30 days). * docs(abacus): add provider documentation and update provider listings Add docs/abacus.md with setup, API details, and troubleshooting for the Abacus AI provider. Add Abacus AI entry to docs/providers.md strategy table and detailed section. Add Abacus AI to README provider list. * test(abacus): add unit tests for Abacus AI provider Add AbacusProviderTests.swift with 23 tests in 3 suites covering: - AbacusDescriptorTests: provider metadata, source modes, CLI config - AbacusUsageSnapshotTests: credit conversion, formatting, edge cases - AbacusErrorTests: error description completeness Uses the Swift Testing framework (@Test + #expect) matching the convention established by recent upstream provider tests. * fix(abacus): hoist paceWindow binding out of if-expression Swift 6.2.4 does not allow let bindings inside the else branch of an if-expression. Move the paceWindow computation before the if-expression to fix compilation. * fix(abacus): tighten session cookie matching to avoid false positives Replace overly broad "id" substring pattern with exact known cookie names (sessionid, auth_token, etc.) checked first, then conservative substring fallback. Prevents selecting unauthenticated cookie sets from browsers that only have analytics cookies for abacus.ai. * fix(abacus): add manual cookie header field to settings UI settingsFields was returning empty array, making Manual cookie mode non-functional. Add secure text field bound to abacusCookieHeader, visible only when cookie source is set to manual, with link to open the Abacus AI dashboard. * fix(abacus): route cookie reads through BrowserCookieAccessGate Use codexBarRecords instead of records directly so the access gate cooldown is consulted before attempting Chromium keychain reads. Also detect session-expired API error payloads and map them to .sessionExpired so cached cookies are properly evicted. * fix(abacus): suppress reset line when billing date unavailable Clear primaryResetText when resetsAt is nil to prevent displaying a misleading "Resets ..." line that duplicates the credit detail. * fix(abacus): remove CSRF from session cookies, propagate billing auth errors Remove csrftoken/csrf_token from knownSessionCookieNames — CSRF tokens exist in anonymous jars and caused false-positive session detection. Also replace try? on billing fetch with explicit error handling that propagates auth errors while tolerating other failures. * fix(abacus): tighten cookie matching and retry on auth failure Remove "token" from fallback substrings (matched csrftoken). Add excludedCookiePrefixes to reject csrf/analytics cookies even on substring match. Change importSession to importSessions returning all candidates so fetchUsage can try each in turn — stale session in first source no longer blocks valid ones further down. * refactor(abacus): comprehensive provider overhaul addressing review feedback Split AbacusUsageFetcher.swift (396 lines) into 4 files matching the Kimi/Perplexity provider pattern: - AbacusCookieImporter.swift — browser cookie extraction - AbacusUsageFetcher.swift — API fetching logic - AbacusUsageSnapshot.swift — data model + conversion - AbacusUsageError.swift — error types Bug fixes: - Pin NumberFormatter locale to en_US (was locale-dependent) - Cached cookie parse failures now clear cache and fall through to fresh browser import instead of aborting - Session loop retries on all recoverable errors (auth + parse), not just auth — prevents one stale source blocking valid ones - Preserve last error on loop exhaustion instead of generic .noSessionCookie - Log billing fetch failures instead of silently discarding - Truncate HTTP response body in error messages (security) - Capture JSON parse error details instead of using try? - Throw parseFailed when critical credit fields missing instead of returning hollow 0% snapshot Architecture alignment: - Add structured CodexBarLog logging (abacusCookie, abacusUsage) - Use cookieImportCandidates(using:) for browser filtering - Accept BrowserDetection parameter for testability - Add hasSession() convenience for isAvailable() check - Improve isAvailable() to probe for actual session existence - Add import AppKit (was implicit via SwiftUI) * fix(abacus): derive pace window from actual billing cycle length Use Calendar to compute the real billing cycle duration (one calendar month before resetsAt) instead of hardcoding 30 days. Falls back to 30-day approximation when resetsAt is nil. Fixes pace drift on 28/31-day months. * fix(abacus): require both credit fields and fix menu bar pace display Require both totalComputePoints and computePointsLeft in API response — partial data no longer silently shows 0% usage. Fall back to primary window for menu bar pace calculation when secondary is nil, so Abacus pace renders in Pace/Both display modes. * fix(abacus): restrict primary-window pace fallback to Abacus only The supportsWeeklyPace guard was too broad — it applied to all pace-capable providers, causing Claude's 5-hour primary window to be misused for pace calculation. Scope the fallback to .abacus which is the only provider using primary window for pace. * fix(abacus): correct dashboard URL in manual cookie settings action Point Open Dashboard to /chatllm/admin/compute-points-usage matching the provider's configured dashboardURL. * fix(abacus): default cookie import to Chrome-only per AGENTS.md AGENTS.md mandates Chrome-only cookie imports by default. Change browserCookieOrder from defaultImportOrder (all browsers) to [.chrome] to avoid unnecessary browser/keychain prompts. * fix(abacus): comprehensive quality pass from multi-agent review Critical fixes: - Remove .parseFailed from isRecoverable (deterministic error, retrying other sessions gives same result) - Fix NumberFormatter thread safety (allocate per call instead of mutating shared static state) High fixes: - Add public init on SessionInfo (API surface parity with peers) - Consistent self. usage throughout fetcher (was mixing Self/self) - Make notSupported public (thrown from public function) - Add Equatable conformance to AbacusUsageError (peer pattern) - Simplify isAuthRelated to delegate to isRecoverable Medium fixes: - Add MARK sections throughout all files - Add #if canImport(FoundationNetworking) guard (Linux compat) - Add explanatory comment on pace fallback in StatusItemController Tests: - Add isRecoverable/isAuthRelated classification tests for all five error cases (28 tests total, 4 suites) * fix(abacus): classify unauthorized JSON errors as auth failures Add unauthorized/unauthenticated/forbidden to the API error keyword detection so JSON-level auth failures (HTTP 200 with success:false) throw .unauthorized instead of .parseFailed. This enables the multi-session fallthrough for stale cookies that return auth errors in the JSON payload rather than via HTTP status codes. * fix(abacus): Chrome-first cookie import with multi-browser fallback Reconcile AGENTS.md Chrome-only guideline with real-world need to support Safari/Firefox users. Match OpenCodeCookieImporter pattern: - Descriptor browserCookieOrder: full defaultImportOrder (all browsers) - AbacusCookieImporter.importSessions: preferredBrowsers: [.chrome] default, empty array falls back to the full descriptor order - fetchUsage: try Chrome first, broaden to all browsers if Chrome yields no sessions - isAvailable: same Chrome-first then fallback probe Users with Chrome get single-browser probe (AGENTS.md compliant); Safari/Firefox users still get their cookies imported when Chrome is absent or empty. * fix(abacus): fall back to all browsers after Chrome auth exhaustion Previously, the all-browsers fallback only triggered when Chrome import threw. If Chrome cookies existed but all returned expired/ unauthorized, the loop exhausted Chrome candidates and returned an auth error without ever trying Safari/Firefox. Extract browser-tier logic into tryFetchFromBrowsers helper; call it first with [.chrome], then with [] (all browsers) if Chrome yielded no valid snapshot for any reason (import failure OR all sessions failing with recoverable errors). * fix(abacus): register in TokenAccountSupportCatalog and bound billing timeout Two issues caught by Codex review: - AbacusSettingsStore referenced TokenAccountSupportCatalog.support( for: .abacus) but no catalog entry existed, so token account overrides were dead code. Add cookie-header injection entry matching the pattern used by other cookie-based providers. - Billing info fetch shared the full 15s timeout with credits. Cap it at min(timeout, 5s) so a slow/flaky billing endpoint doesn't delay credit rendering — billing is optional anyway. * Improve Abacus web fetch error handling * Harden Abacus web fetch fallbacks * Fix Abacus lint failure * Fix provider order test for Abacus * Fallback after stale Abacus cache failures * Handle Abacus fetch concurrency with sendable task results --------- Co-authored-by: Christian C. Berclaz <christian.berclaz@mac.com>
2.5 KiB
summary, read_when
| summary | read_when | |||
|---|---|---|---|---|
| Abacus AI provider: browser cookie auth for ChatLLM/RouteLLM compute credit tracking. |
|
Abacus AI Provider
The Abacus AI provider tracks ChatLLM/RouteLLM compute credit usage via browser cookie authentication.
Features
- Monthly credit gauge: Shows credits used vs. plan total with pace tick indicator.
- Reserve/deficit estimate: Projected credit usage through the billing cycle.
- Reset timing: Displays the next billing date from the Abacus billing API.
- Subscription tiers: Detects Basic and Pro plans.
- Cookie auth: Automatic browser cookie import (Safari, Chrome, Firefox) or manual cookie header.
Setup
- Open Settings → Providers
- Enable Abacus AI
- Log in to apps.abacus.ai in your browser
- Cookie import happens automatically on the next refresh
Manual cookie mode
- In Settings → Providers → Abacus AI, set Cookie source to Manual
- Open your browser DevTools on
apps.abacus.ai, copy theCookie:header from any API request - Paste the header into the cookie field in CodexBar
How it works
Two API endpoints are fetched concurrently using browser session cookies:
GET https://apps.abacus.ai/api/_getOrganizationComputePoints— returnstotalComputePointsandcomputePointsLeft(values are in credit units, no conversion needed).POST https://apps.abacus.ai/api/_getBillingInfo— returnsnextBillingDate(ISO 8601) andcurrentTier(plan name).
Cookie domains: abacus.ai, apps.abacus.ai. Session cookies are validated before use (anonymous/marketing-only cookie sets are skipped). Valid cookies are cached in Keychain and reused until the session expires.
The billing cycle window is set to 30 days for pace calculation.
CLI
codexbar usage --provider abacusai --verbose
Troubleshooting
"No Abacus AI session found"
Log in to apps.abacus.ai in a supported browser (Safari, Chrome, Firefox), then refresh CodexBar.
"Abacus AI session expired"
Re-login to Abacus AI. The cached cookie will be cleared automatically and a fresh one imported on the next refresh.
"Unauthorized"
Your session cookies may be invalid. Log out and back in to Abacus AI, or paste a fresh Cookie: header in manual mode.
Credits show 0
Verify that your Abacus AI account has an active subscription with compute credits allocated.