Skip to content

Add the Muse (muse.ai) provider - #814

Merged
Finesssee merged 52 commits into
mainfrom
feat/provider-museai
Oct 11, 2026
Merged

Finesssee merged 52 commits into
mainfrom
feat/provider-museai

Conversation

@Finesssee

@Finesssee Finesssee commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #821; merge in order 808 → 810 → 818 → 819 → 821 → 814 → 817; the diff shows predecessors until they merge.

What users get

A new Muse (muse.ai) provider for Meta's personal agent at muse.ai. It is separate from the existing Muse Code provider (muse), and it is disabled by default.

Cookie source. Settings → Providers → Muse (muse.ai) has a cookie-source picker that defaults to Automatic:

  • Automatic and Manual first use a header imported under Browser Cookies (from the browser you choose) or pasted there.
  • Without a stored header, Automatic reads the muse.ai cookies from the first detected browser that has them, and Manual fails closed without reading a browser.
  • Off reads nothing.

The card shows:

  • Weekly usage as the primary lane, with its reset
  • the plan (Free, Power or Maximum) and, on paid plans, the "tokens left" text (for example "1.9B tokens left")
  • Additional tokens (top-up) as an extra bar when the account has a top-up balance

Ported from upstream CodexBar v0.73.0 Resources/Plugins/museai.js and Providers/MuseAI/MuseAIProviderDescriptor.swift. muse.ai has no usage API, so the provider posts the settings dialog's Next.js server action fetchSubscriptionAction to https://muse.ai/ with the session cookies. The action ID changes on every deploy. A 404 Server action not found. starts a bounded discovery through the page's chunks: at most 96 page chunks, eight at a time, 8 MiB in total, then at most 32 settings chunks. Static chunks get no cookies. A 401, a 403 or a redirect to auth.muse.ai is reported as an expired session. Cookies and response bodies are never logged or echoed in errors.

Files

  • rust/src/providers/museai/{mod.rs,model.rs,tests.rs}: fetch, action discovery, flight-response parse and card mapping

  • Wiring per the new-provider recipe:

    • core/provider.rs: ProviderId::MuseAI (cli museai, display "Muse (muse.ai)", cookie domain muse.ai, colour #0668E1)
    • core/provider_factory.rs: factory arm
    • core/token_accounts.rs: None arm
    • providers/mod.rs
  • Frontend: ProviderIcon-museai.svg, providerIcons.ts, test/providerCatalog.ts

  • Docs: docs/PROVIDERS.md (new "Muse (muse.ai) weekly usage" section), README.md (provider table row)

  • Cookie-source picker (second commit, following the Groq precedent in 5a44b63):

    • commands/provider_settings.rs: Automatic / Manual / Off options and the id mapping
    • rust/src/settings.rs: the default cookie source is "auto" (before this, the default "manual" plus the provider's fail-closed policy meant Automatic could never be reached)
    • tests in rust/src/settings/tests.rs and commands/session_cookie_scope_tests.rs

No i18n or dependency changes; the picker reuses the existing option labels.

Tests

26 tests in museai/tests.rs (15 unit, 11 local-server). They use fixed fixtures and assert literal values:

  • Plans: Maximum (weekly, tokens left, renewal, top-up), Power, and Free (no tokens, renewal or top-up). The parity-pack payload maps to Power at 34%.
  • Top-up: unlabeled micro-dollar balance shown in USD; a label without a token count is kept verbatim; a zero total hides it.
  • Parsing: usage is clamped; the plan falls back to the usage-row label; the last successful flight row wins; CRLF lines parse; invalid responses are parse errors.
  • Discovery: chunk paths are prefixed and deduplicated in page order; the settings loader lists only the preloaded module files; the action ID is read from the server reference.
  • Local server:
    • a stored action posts once with browser fetch headers
    • missing or stale actions are rediscovered and saved
    • sign-in redirects and a forbidden action report an expired session
    • a signed-out stored action keeps its ID
    • page-chunk and settings-chunk requests are capped
    • a failed rediscovery or an invalid response never caches the action
    • non-success statuses name the HTTP code without the body
    • Off and OAuth make no requests
    • a missing manual cookie asks for sign-in
  • Metadata: distinct from Muse Code.

Two more tests cover the picker:

  • museai_cookie_source_defaults_to_automatic_session_import (settings): the default is "auto".
  • museai_exposes_a_cookie_source_picker_and_routes_each_choice (tauri): the options are [auto, manual, off]; a stored header is used under Automatic and Manual; an empty Manual source is Web with manual_cookie_missing; Off reaches the provider as Cli with no header.

Commands

Command Result
cargo fmt --all -- --check pass
cargo test --manifest-path rust/Cargo.toml pass (3829 passed, 1 ignored)
cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings pass
cargo test --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml pass (638)
cargo clippy --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml --all-targets -- -D warnings pass
pnpm test pass (107 files, 831 tests)
pnpm run lint pass (only existing warnings, none in changed lines)
pnpm run build pass

The cargo rows ran on the head commit (8a4c5a3). The pnpm rows ran on the first commit (e584848); the picker commit touches no frontend files.

The branch is based on 44d5de3, and the checks ran on that base. It predates #813 (the Mac card anatomy), so the panel proof and the card-layout gaps below describe the card before #813. Main's later Providers-pane changes (the usage-details section and #816's Settings panes) don't touch the cookie-source or API-key sections, and cookie_source_options_for and the API-key catalog are unchanged on main.

Proof (Windows, synthetic data only)

  • Build: a debug build of this branch's commit (e584848), made through the parity rig (build-proof.sh). The proof-shim patch is never committed.
  • Capture: win_run.py with the MuseAI scenario pack. It uses a synthetic manual cookie and a mocked muse.ai: the page, three chunks and the action POST, all 200.
  • Files:
    • Windows panel: W:/mac-parity/report/provider-museai/panel.png
    • comparison: W:/mac-parity/report/provider-museai/COMPARISON.md
    • result.json, mock.log in the same folder
  • Result:
    • "Muse (muse.ai)", plan Power, "Weekly 66% left", "Resets in 3d 12h" and "1.9B tokens left"
    • "Additional tokens 75% left" with "1.5B tokens left"
    • all of these match the values the pack derives from museai.js
  • Settings picker: win_run.py --mode settings:providers --target settings with a copy of the pack that lists this provider first (W:/mac-parity/report/provider-museai/settings-pack/).
    • Before, on the first commit (e584848): the provider pane has no "Cookie source" section. W:/mac-parity/report/provider-museai/settings-proof/settings-before.png and .json
    • After, on the head commit (8a4c5a3): the pane shows "Cookie source" with Automatic, Manual (selected, from the pack's settings) and Disabled. W:/mac-parity/report/provider-museai/settings-proof/settings-after.png and .json
    • The panel proof above still holds: the pack sets the Manual source with a synthetic header, so the picker commit does not change its routing or the card.

Gaps vs the Mac card

  • No Mac capture exists: muse.ai arrived upstream in 0.71.0, after the 0.70.0 Mac baseline. The comparison is against the pack's expected values.
  • Renewal date not shown: it is parsed into subscription metadata, but the card does not render it.
  • Top-up layout: top-up tokens show as a second bar; upstream has a detail row with a progress value.
  • Pace lines: the shared Windows card adds pace/reserve lines for the 7-day window.
  • Action ID in memory: it lasts for the app session; upstream stores it on disk, so the first refresh after a restart rediscovers it.
  • User-Agent: Windows sends a Windows Chrome 143 User-Agent; upstream sends the macOS one.
  • One session per refresh:
    • Automatic tries the first detected browser that has muse.ai cookies and does not fall through to the next after a failure.
    • An empty Manual source fails closed instead of reading browser cookies.
    • Upstream's Automatic imports from Chrome only; an explicit import under Browser Cookies can pick any supported browser.
  • No dataConfidence equivalent (upstream marks the data percentOnly).
  • Chunk limits: an oversized chunk reads as empty, and the 8 MiB discovery cap counts bytes.
  • English only: detail strings are not translated.

Sibling PR conflicts

This is one of seven provider PRs: Synthetic (#808), ClawRouter (#810), IBM Bob (#818), Langdock (#819), LithosAI (#821), MuseAI (#814) and WorkBuddy (#817). They all add lines at the same anchors, so expect trivial textual conflicts once one of them merges. Keep both sides. The shared anchors are:

  • ProviderId lists in core/provider.rs (after Vercel), including the all().len() count in its test
  • the factory arm and providers/mod.rs
  • token_accounts.rs
  • providerCatalog.ts and the providerIcons.ts registry
  • the docs/PROVIDERS.md section and README table rows

The four cookie providers (Langdock #819, LithosAI #821, MuseAI #814 and WorkBuddy #817) also share the picker commit's anchors, so they conflict with each other there:

  • rust/src/settings.rs: each PR rewrites the default cookie-source arm Kimi | Hyper | Groq => "auto" to add its variant. Keep every variant in the arm.
  • commands/provider_settings.rs: each PR adds lines after the groq entries in cookie_source_provider and cookie_source_options_for.
  • rust/src/settings/tests.rs: each PR adds a default test after the Groq default test.
  • commands/session_cookie_scope_tests.rs: each PR appends a test at the end of the file.

@coderabbitai

coderabbitai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: nesszer/Win-CodexBar/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 3ee2a4f5-d06a-4b3e-89cf-9af88468cf06

📥 Commits

Reviewing files that changed from the base of the PR and between 5f6199a and 134e8a5.


⛔ Files ignored due to path filters (6)
  • apps/desktop-tauri/src/components/providers/icons/ProviderIcon-clawrouter.svg is excluded by !**/*.svg
  • apps/desktop-tauri/src/components/providers/icons/ProviderIcon-ibmbob.svg is excluded by !**/*.svg
  • apps/desktop-tauri/src/components/providers/icons/ProviderIcon-langdock.svg is excluded by !**/*.svg
  • apps/desktop-tauri/src/components/providers/icons/ProviderIcon-lithosai.svg is excluded by !**/*.svg
  • apps/desktop-tauri/src/components/providers/icons/ProviderIcon-museai.svg is excluded by !**/*.svg
  • apps/desktop-tauri/src/components/providers/icons/ProviderIcon-synthetic.svg is excluded by !**/*.svg

📒 Files selected for processing (47)
  • README.md
  • apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs
  • apps/desktop-tauri/src-tauri/src/commands/session_cookie_scope_tests.rs
  • apps/desktop-tauri/src/components/providers/providerIcons.test.ts
  • apps/desktop-tauri/src/components/providers/providerIcons.ts
  • apps/desktop-tauri/src/i18n/keys.ts
  • apps/desktop-tauri/src/surfaces/settings/providers/sections/WayfinderGatewaySection.test.tsx
  • apps/desktop-tauri/src/surfaces/settings/providers/sections/WayfinderGatewaySection.tsx
  • apps/desktop-tauri/src/test/providerCatalog.ts
  • docs/PROVIDERS.md
  • rust/src/core/provider.rs
  • rust/src/core/provider_factory.rs
  • rust/src/core/token_accounts.rs
  • rust/src/locale.rs
  • rust/src/locale/en-US.ftl
  • rust/src/locale/es-MX.ftl
  • rust/src/locale/ja-JP.ftl
  • rust/src/locale/ko-KR.ftl
  • rust/src/locale/pt-BR.ftl
  • rust/src/locale/ru-RU.ftl
  • rust/src/locale/tests.rs
  • rust/src/locale/tr-TR.ftl
  • rust/src/locale/uk-UA.ftl
  • rust/src/locale/zh-CN.ftl
  • rust/src/locale/zh-TW.ftl
  • rust/src/providers/clawrouter/mod.rs
  • rust/src/providers/clawrouter/model.rs
  • rust/src/providers/clawrouter/tests.rs
  • rust/src/providers/ibmbob/fixtures/profile.json
  • rust/src/providers/ibmbob/mod.rs
  • rust/src/providers/ibmbob/model.rs
  • rust/src/providers/ibmbob/tests.rs
  • rust/src/providers/langdock/mod.rs
  • rust/src/providers/langdock/model.rs
  • rust/src/providers/langdock/tests.rs
  • rust/src/providers/lithosai/mod.rs
  • rust/src/providers/lithosai/model.rs
  • rust/src/providers/lithosai/tests.rs
  • rust/src/providers/mod.rs
  • rust/src/providers/museai/mod.rs
  • rust/src/providers/museai/model.rs
  • rust/src/providers/museai/tests.rs
  • rust/src/providers/synthetic/mod.rs
  • rust/src/providers/synthetic/tests.rs
  • rust/src/settings.rs
  • rust/src/settings/api_keys.rs
  • rust/src/settings/tests.rs

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This was referenced Oct 11, 2026
# Conflicts:
#	apps/desktop-tauri/src/components/providers/providerIcons.ts
#	apps/desktop-tauri/src/test/providerCatalog.ts
#	docs/PROVIDERS.md
#	rust/src/core/provider.rs
#	rust/src/core/provider_factory.rs
#	rust/src/core/token_accounts.rs
#	rust/src/settings/api_keys.rs
# Conflicts:
#	apps/desktop-tauri/src/components/providers/providerIcons.ts
#	apps/desktop-tauri/src/test/providerCatalog.ts
#	docs/PROVIDERS.md
#	rust/src/core/provider.rs
#	rust/src/core/provider_factory.rs
#	rust/src/settings/api_keys.rs
# Conflicts:
#	README.md
#	apps/desktop-tauri/src/components/providers/providerIcons.ts
#	apps/desktop-tauri/src/test/providerCatalog.ts
#	rust/src/core/provider.rs
#	rust/src/core/provider_factory.rs
#	rust/src/core/token_accounts.rs
# Conflicts:
#	README.md
#	apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs
#	apps/desktop-tauri/src-tauri/src/commands/session_cookie_scope_tests.rs
#	apps/desktop-tauri/src/components/providers/providerIcons.ts
#	apps/desktop-tauri/src/test/providerCatalog.ts
#	docs/PROVIDERS.md
#	rust/src/core/provider.rs
#	rust/src/core/provider_factory.rs
#	rust/src/core/token_accounts.rs
#	rust/src/settings.rs
#	rust/src/settings/tests.rs
# Conflicts:
#	README.md
#	apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs
#	apps/desktop-tauri/src-tauri/src/commands/session_cookie_scope_tests.rs
#	apps/desktop-tauri/src/components/providers/providerIcons.ts
#	apps/desktop-tauri/src/test/providerCatalog.ts
#	docs/PROVIDERS.md
#	rust/src/core/provider.rs
#	rust/src/core/provider_factory.rs
#	rust/src/core/token_accounts.rs
#	rust/src/settings.rs
#	rust/src/settings/tests.rs
- Automatic cookie source: the provider now owns browser cookie
  resolution. It reads every detected browser's langdock.com cookies and
  uses the first one with a non-empty auth_token (upstream
  requiredCookies), instead of the shell's first browser with any
  langdock.com cookie. Manual headers and an empty Manual or Off source
  never read a browser.
- No included limits: one informational primary labelled "Included
  limits" (upstream detail title) with no duplicate detail row, so the
  card no longer shows the message twice under "Session".
- Correct the overage comment: RateWindow clamps when the window is
  built, not at display time.
- A missing key (shared resolve_api_key NotInstalled) now maps to upstream
  IBMBobUsageFetcher's "Missing IBM Bob API key. Add one in Settings or set
  BOBSHELL_API_KEY." instead of the generic "API key not found" text; before,
  only a blank key reached it. Other resolver errors still propagate.
- New pure helper api_key_from; hermetic test a_missing_key_uses_the_ibm_bob_message.
- HTTP 401/403 ("ClawRouter rejected the API key...") now maps to
  NeedsAuthentication via error_state_kind, matching upstream's
  authenticationExpired; the message text is unchanged and other
  errors keep the default mapping.
- HTTP tests no longer read CLAWROUTER_BASE_URL: the env fallback is an
  injected lookup that the test constructor disables.
- Port upstream's budgeted golden fixture (0.024% used, $25 limit,
  openai before anthropic, reset 2026-08-01Z) as a literal test.
- Omit the Prepaid credits cost block for a negative balance. The shared
  block floors balances at zero, so a debt showed "$0.00"; the primary
  line and Balance row keep "-$1.00" (upstream keeps debts visible).
- Own browser cookie resolution: Automatic now tries every browser that
  holds both __Host-console_session and __Host-console_csrf, in order,
  and moves to the next after a 401 at any request (upstream
  rejectCookie). A pasted header is still the only session tried, an
  empty Manual source still fails closed, and Off is unchanged.
- When no browser session is usable and the browser read itself failed
  (for example App-Bound Encryption), report that error instead of the
  generic sign-in hint.
- Stop attaching the weekly USD CostSnapshot to the fetch result. Upstream
  SyntheticProviderDescriptor hides the cost block on the card
  (ProviderCostPresentation(menuCardStyle: .hidden)), and core has no
  per-provider "hidden on card" flag. The parsed credits still drive the
  weekly regen line. As a result the weekly cost also leaves CLI JSON.
  QuotaCost.resets_at was only used for that snapshot and is removed.
- Port upstream's "Synthetic fixture matches the cut-over golden"
  (ProviderPluginParityTests.swift) and "missing rolling lane keeps weekly
  and search slots" (SyntheticProviderTests.swift) as literal tests.
  Weekly used percent is 1.9411527777777593, not upstream's
  1.9411527777777735: serde_json without float_roundtrip reads
  98.05884722222223 one ULP high (1.4e-14, never visible).
- Use the fixed NOW in the bearer-request test instead of Utc::now().
- docs/PROVIDERS.md: the weekly credits no longer give a USD cost.
- The top-up balance was mapped to an extra RateWindow ("topup"), so the
  card drew it as a second quota bar with pace lines. Upstream museai.js
  returns it as a detail row {label, value, progress}; map it to a
  ProviderDisplayDetail with progress (used fraction of 1.0) instead.
- Tests assert extra_rate_windows stays empty and the detail row carries
  "Additional tokens" / "1.5B tokens left" / progress 0.25, the "$80.00 left"
  fallback, the verbatim label and the zero-total case.
- docs/PROVIDERS.md: describe the top-up as a detail row.
Synthetic's Mac brand color #141414 is near-black, so the palette's
brandColorOnDark lifts it on dark surfaces like v0 and TypeSafe; list it
in the registry test.
# Conflicts:
#	apps/desktop-tauri/src/components/providers/providerIcons.ts
# Conflicts:
#	apps/desktop-tauri/src/components/providers/providerIcons.ts
# Conflicts:
#	apps/desktop-tauri/src/components/providers/providerIcons.ts
# Conflicts:
#	apps/desktop-tauri/src/components/providers/providerIcons.ts
# Conflicts:
#	apps/desktop-tauri/src/components/providers/providerIcons.ts
@Finesssee
Finesssee merged commit e9203d5 into main Oct 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant