feat: add Muse (Meta) provider - #2936
Conversation
- Adds UsageProvider.muse with API-key auth (MUSE_API_KEY / META_API_KEY / META_MUSE_API_KEY) - Balance-only provider with flexible billing probe (billing/usage, me/balance, credits) falling back to /v1/models validation - Supports custom base URL via MUSE_API_URL or Settings for proxies/self-hosted gateways - Registers descriptor, fetch strategy, settings UI, icon, and docs/muse.md - Regenerates manifests (ProviderManifest, ProviderImplementationManifest, provider-ids) Fixes: Muse API not visible in CodexBar. Pricing is $1.25/4.25 per 1M tokens via api.meta.ai; this provider validates the key and shows balance where the API exposes it.
|
🦞👀 Pull request received. I will update this pull request when review starts. |
- widgetFingerprint 16873014858015536126 -> 1384715300343528903 - burnDownFingerprint 8686456525451224704 -> 5817880812814024010 - balanceOnly set now includes .muse alongside deepseek/deepinfra/mistral/moonshot/poe
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3bc93d6c2d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| widgetSelectable: false, | ||
| isPrimaryProvider: false, | ||
| usesAccountFallback: false, | ||
| balanceOnly: true, |
There was a problem hiding this comment.
Update the balance-only gatekeeper set
Setting balanceOnly here adds .muse to descriptors.filter(\.metadata.balanceOnly), but ProviderArchitectureGatekeeperTests.swift:196-198 still asserts the exact set without Muse, so the full test suite will deterministically fail. Update that fixture and add focused Muse coverage alongside the new provider.
AGENTS.md reference: AGENTS.md:L20-L24
Useful? React with 👍 / 👎.
| primary: nil, | ||
| secondary: nil, | ||
| tertiary: nil, | ||
| providerCost: nil, |
There was a problem hiding this comment.
Expose the Muse balance to the menu-bar renderer
When a billing endpoint returns a balance, this snapshot leaves all rate/detail fields nil and stores the value only in identity.loginMethod. StatusItemController.menuBarDisplayText has explicit extraction branches for every existing balance-only provider but none for .muse, so it falls through with no percent window and returns no balance text when Muse is selected in the menu bar. Add a Muse balance extractor or represent the balance in a field consumed by the generic renderer.
Useful? React with 👍 / 👎.
| } catch { | ||
| if let last = lastError { throw last } | ||
| throw error |
There was a problem hiding this comment.
Preserve authentication errors from the models probe
If any speculative billing endpoint first returns a non-404 error or an unparseable 2xx response, lastError is populated; if the authoritative models probe then returns 401/403, this catch discards its explicit “invalid API key” error and reports the stale billing error instead. This misdiagnoses invalid credentials whenever an earlier optional billing probe failed, so authentication errors from the fallback probe should take precedence.
Useful? React with 👍 / 👎.
|
Codex review: found issues before merge. Reviewed August 16, 2026, 9:46 AM ET / 13:46 UTC. ClawSweeper reviewWhat this changesThis PR adds a Meta Muse provider that fetches API-key balance data and optionally reads Team usage from the dev.meta.ai browser dashboard. Merge readiness⛔ Blocked by patch quality or review findings - 10 items remain Keep open: the feature is not on current main, but the browser-session path needs a product decision and still has two concrete merge blockers. Priority: P1 Review scores
Verification
How this fits togetherCodexBar turns provider credentials or browser sessions into usage snapshots consumed by the menu bar and settings UI. The Muse provider adds Meta API and dashboard fetch paths to that shared pipeline. flowchart LR
A[API key or browser session] --> B[Muse provider]
B --> C[API or dashboard fetch]
C --> D[Meta endpoints]
D --> E[Usage snapshot]
E --> F[Menu bar and settings]
Decision needed
Why: The API path is a bounded provider integration, but the web path imports sensitive browser sessions and depends on an internal dashboard contract that needs explicit ownership. Before merge
Findings
Agent review detailsSecurityNeeds attention: The automatic web path can transmit imported cookies beyond their browser-enforced origin and path scope. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Keep the API-key balance/validation path, and retain dashboard usage only if a maintainer sponsors it after destination-safe cookie handling, Chrome-only automatic import, and focused regression coverage. Do we have a high-confidence way to reproduce the issue? Not applicable as a feature request; the contributor nevertheless supplied a redacted terminal run showing the real Meta dashboard path. Is this the best way to solve the issue? No—the API-key path is bounded, but the browser-session implementation should not land until its cookie boundary is fixed and maintainers explicitly accept the internal-dashboard dependency. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against b9ae578fb101. LabelsLabel changes:
Label justifications:
EvidenceSecurity concerns:
What I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (16 earlier review cycles; latest 8 shown)
|
…uard - P1: add museBalanceDisplayText and menuBarDisplayText branch for .muse so balance/probe result from loginMethod is rendered (mirrors moonshot/poe). Fixes empty menu-bar text. - P2: preserve authoritative 401/403 from /v1/models probe over stale billing lastError. - P2/security: validate base URL — require https, allow only http://localhost/127.0.0.1/::1 for local proxy, reject insecure hosts before sending Bearer token.
- StatusItemController+Animation.swift:923 now clusters mistral+kiro+cursor (3) instead of kiro+cursor (2) after inserting muse branch at 917; add Provider-specific by design comment to justify the expanded window. - Tests: update AllowedProviderConstruct at 926->923, anchor kiro->mistral, fingerprint [kiro@0,cursor@8]/2 -> [mistral@0,kiro@9,cursor@17]/3. Gatekeeper now 38/38 pass.
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
- parseModelsCount now throws parseFailed when data/models array is missing instead of returning nil and incorrectly reporting 'API key valid'.
- ClawSweeper auth-provider finding: prevents {} from being accepted as successful validation.
- MuseUsageFetcher: require numeric balance for billing success (currency-only now correctly falls through to models probe instead of false 'API key valid'). Fixes P2 at 253-254.
- Tests: add MuseUsageFetcherTests (12 cases) covering balance parsing, empty/currency-only rejection, models count and rejection of {} / missing array, Bearer/Accept/timeout headers, https guard (evil.com blocked, localhost allowed), 401 precedence over 500, balance preferred over fallback, and missing key. Provides controlled-transport coverage for the 319-line fetcher.
- README, docs/providers.md, docs/social.html, docs/llms.txt, docs/index.html, docs/site-locales.mjs: 69 -> 70 providers after Muse addition (check-site-locales.mjs requires exact count) - docs/providers.md: add Muse table row + detailed section - MuseUsageFetcher: refactor Generic decode + fallback scan to nil-coalescing to satisfy statement_position lint, fix multiline_parameters for fetchBalance - MuseProviderDescriptor: split noDataMessage for line_length - MuseSettingsReader: explicit self (redundantSelf) - MuseUsageFetcherTests: fix encoded delimiter test to use %2F (hostHasNoEncodedDelimiters only rejects %2f/%40 etc, not %2e), fix fatalError message - ProviderArchitectureGatekeeperTests: line 923->924 after comment wrap (line_length) shifted mistral anchor - StatusItemController+Animation: comment wrap from swiftformat make check: PASS (0 violations), swift build PASS, swift test MuseUsageFetcherTests 15/15 PASS, ProviderArchitectureGatekeeper 38/38 PASS
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Replace guessed GET /api/usage* probes (all 404) with POST https://dev.meta.ai/api/graphql/ doc_id 27710687895239709 (LLMDCUsageQuery) reverse-engineered from HAR. Harvest team_id/LSD/fb_dtsg/__rev/__hsi from dashboard HTML, build form-urlencoded RelayModern body with week window (America/Chicago), handle for(;;); wrapper and recursive token/cost/request parsing. Fall back to HTML only if GraphQL yields no metrics. Fixes web auto falling back to apiToken showing only 3 models.
dev.meta.ai dashboard auth rides on facebook.com session cookies (c_user/xs/datr) not just meta.ai. All Chrome profiles show 0 rows for meta.ai domains. Expand cookieDomains to facebook.com/www.facebook.com/meta.com so MuseWebFetchStrategy can build the GraphQL Cookie header.
Safari legacy cookie stages but HTML has teamId as integer or URL-encoded without quotes. Expand extractTeamId patterns to cover "teamId":374..., teamId%3D, and bare numeric team_id/teamId with 10+ digits.
Replace generic total_tokens search with parseTeamUsage that sums categorical_data for num_requests/num_prompt_tokens/ num_completion_tokens/usage_billable_cost (amount_with_offset cents->dollars) per verified 2026-08-15 GraphQL response (4814 req / 589M prompt / .59). Produces Team usage snapshot with cost.
ff10147 to
ddc68d3
Compare
Manual cookie (llm_sess+datr) harvests no team_id/fb_dtsg from HTML, causing 1357004. Use verified HAR fallbacks swTyN9fDdqKU_GTgO9R99v / NAfztM7dBcJpLZ... for GraphQL.
|
Verified via ```
$ curl https://dev.meta.ai/api/graphql/ -b "datr=...; llm_sess=..." --data-raw "doc_id=27710687895239709&variables={"team_id":"3747295692075251",...}" $ codexbar config dump --show-secrets | grep muse Fallback remains Branch |
Build dailyPoints from categorical_data (prompt+output tokens + cost per day) and expose as ProviderDetailSection Daily usage table in UsageSnapshot.details for the Muse detail sheet.
Use UsageFormatter.tokenCountString for tokens (623M vs 622576992) and NumberFormatter decimal/currency for requests and cost per Locale.current. Applies to main snapshot, fallback parseUsageAPI and daily detail rows.
Summary
Adds native Muse (Meta) support to CodexBar — previously un-tracked. Muse's Meta Model API (
https://api.meta.ai, modelmuse-spark-1.1, pricing$1.25/$4.25per 1M) had no provider; users proxying via OpenRouter paid the 5.5% credit fee and lost direct visibility.Provider design
MUSE_API_KEY/META_API_KEY/META_MUSE_API_KEYenv or~/.codexbar/config.json(museapiKey). Projects toMUSE_API_KEYfor CLI (codexbar usage --provider muse).https://api.meta.ai, overridable via Settings → Providers → Muse → API base URL orMUSE_API_URL(enables LiteLLM/self-hosted proxies while keeping visibility). Validated viaProviderEndpointOverrideValidator().validatedURLAllowingLoopbackHTTP— requireshttps://, allows onlyhttp://localhost/127.0.0.1/::1for local proxy, rejects user info (user:pass@host), encoded host delimiters (%2f/%40etc.), missing/unsafe hosts, before sendingAuthorization: Bearer. Covered by focused tests.MuseAPIFetchStrategy(.apionly) →MuseUsageFetcher:/v1/billing/usage,/v1/me/balance,/v1/billing/subscription,/v1/credits— flexible JSON parser handlesavailable_balance/balance/total_balance(string or number) in root ordataenvelope. Rejects currency-only payloads (requires numeric balance).GET /v1/modelsvalidation — returnsAPI key valid · N models availablewhen billing is not yet exposed. Both paths useAuthorization: Bearer <key>, 15s timeout, 404 tries next, 401/403 surfaces as invalid key (models-probe 401 now takes precedence over stale billing lastError). Rejects malformed{}withparseFailed: Models response missing data/models arrayinstead of incorrectly reportingAPI key valid.balanceOnly: true(identity-only, no rate windows) — pay-as-you-go API, consistent with Moonshot/DeepSeek billing-only providers.https://ai.developer.meta.com/. Branding: Meta blue#0064E0, confetti[#0064E0, #0469FF, #7B61FF], iconProviderIcon-muse.svg. AddedmuseBalanceDisplayText+menuBarDisplayTextbranch for.museso balance renders (mirrorsmoonshot/poe).Files
Sources/CodexBarCore/Providers/Muse/MuseProviderDescriptor.swift— descriptor +MuseAPIFetchStrategy+ProviderConfig.baseURLextension (nowpublic)Sources/CodexBarCore/Providers/Muse/MuseUsageFetcher.swift— HTTP + parsers for balance + models count, shared validator, preserved 401 handling, malformed{}rejectionSources/CodexBarCore/Providers/Muse/MuseSettingsReader.swift— env resolution for keys + base URLSources/CodexBarCore/Providers/Muse/MuseProviderSettings.swift—MuseProviderSettings+MuseProviderSettingsKeySources/CodexBar/Providers/Muse/MuseProviderImplementation.swift— UI hooks, availability, settings fieldsSources/CodexBar/Providers/Muse/MuseSettingsStore.swift—SettingsStoreextension for token + baseURLSources/CodexBar/Resources/ProviderIcon-muse.svg— iconSources/CodexBar/StatusItemController+Animation.swift—museBalanceDisplayText+ menu-bar branch, plus// Provider-specific by designfor expandedmistral+kiro+cursorclusterdocs/muse.md— provider docs (data sources, endpoints, key files, CLI)docs/providers.md— added Muse row + detailed section (70 providers total)Sources/CodexBarCore/Providers/Providers.swift—case museProviderManifest.swift,ProviderImplementationManifest.swift,ProviderInstanceIDAliases.generated.swift,docs/provider-ids.mdviaScripts/regenerate-provider-manifests.shREADME.md,docs/social.html,docs/llms.txt,docs/index.html,docs/site-locales.mjs(69->70) percheck-site-locales.mjsTests/CodexBarTests/ProviderArchitectureGatekeeperTests.swift— updatedwidgetFingerprint/burnDownFingerprintandbalanceOnly+ allowlisted cluster (mistral@0,kiro@9,cursor@17at 924)Tests/CodexBarTests/MuseUsageFetcherTests.swift— 15 tests: balance shapes, currency-only rejection, models count, malformed{}, Bearer header, https guard, user-info/encoded/missing-host rejection, http localhost allowed, 401 precedence, balance 200 preferredVerification
make check— PASS (0 violations, 0 serious in 1882 files)swift build— passswift test --filter ProviderArchitectureGatekeeper— 38/38 passswift test --filter MuseUsageFetcherTests— 15/15 passScripts/regenerate-provider-manifests.sh --check—Provider manifests are current (70 providers)Follow-ups
Meta billing endpoint is not publicly documented in
ai.developer.meta.com/docs; parser is intentionally lenient and the models-probe fallback guarantees the provider is useful on day one.Fixes: adds Muse alongside existing
openrouter/litellmoptions so users no longer need to pay OpenRouter 5.5% just for visibility.Contribution guide compliance
UsageProvidercase, descriptor inCodexBarCore, implementation inCodexBar,regenerate-provider-manifests.sh, icon, widgetSelectable false, focused tests,docs/muse.md+docs/providers.mdentrymake check(SwiftFormat + SwiftLint) — 0 violations