Skip to content

Add the IBM Bob provider - #818

Open
Finesssee wants to merge 20 commits into
mainfrom
feat/provider-ibmbob
Open

Finesssee wants to merge 20 commits into
mainfrom
feat/provider-ibmbob

Conversation

@Finesssee

@Finesssee Finesssee commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

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

What users get

A new IBM Bob provider for monthly Bobcoin usage.

Setup. Add an API key from the IBM Bob web portal in either of these places:

  • Settings → Providers → IBM Bob
  • the provider's token accounts, which store multiple labelled keys

Alternatively, set BOBSHELL_API_KEY. The CLI also accepts ibmbob, ibm-bob, ibm bob, bob and bobshell.

The card shows:

  • Monthly Bobcoins as the primary lane. It sums every team the key can see and resets at the earliest refresh_at. When any team has no budget, the lane shows Bobcoins used instead of a percentage.
  • Bobcoin usage rows, one per team ("Instance · Team", used / limit Bobcoins, plan).
  • "API key" as the identity, with the plan names as the organization.
  • Usage Dashboard (bob.ibm.com) and Status Page (status.bob.ibm.com) links.

Port and requests. Ported from upstream CodexBar v0.73.0 IBMBobUsageFetcher.swift, IBMBobSettingsReader.swift and IBMBobProviderDescriptor.swift. Each refresh:

  1. Reads GET https://api.us-east.bob.ibm.com/admin/v1/profile.
  2. Reads each team's budget from GET /admin/v1/teams/{team}/users/{user} on the instance's regional host.

Security.

  • Credentials go only to HTTPS hosts named bob.ibm.com or under .bob.ibm.com. Any other region_domain stops the refresh before a team request.
  • Redirects are not followed.
  • A JWT session token is sent as Bearer, any other key as Apikey.
  • 401 and 403 report a rejected key.
  • Response bodies are never echoed in errors, and the key is never logged.

Files

  • rust/src/providers/ibmbob/{mod.rs,model.rs,tests.rs,fixtures/profile.json}: fetch, regional-host validation, parse and card mapping
  • Wiring per the new-provider recipe:
    • core/provider.rs: ProviderId::IBMBob (cli ibmbob, aliases ibm-bob, ibm bob, bob, bobshell; colour #0E61FA)
    • core/provider_factory.rs: factory arm
    • providers/mod.rs
    • settings/api_keys.rs: catalog entry and help text
    • core/token_accounts.rs: token-account support that injects BOBSHELL_API_KEY, plus a test
  • Frontend: ProviderIcon-ibmbob.svg, providerIcons.ts, test/providerCatalog.ts
  • Docs: docs/PROVIDERS.md (new IBM Bob section), README.md (provider table row)

No i18n or dependency changes.

Tests

19 tests in ibmbob/tests.rs (13 unit, 6 local-server), plus 1 in token_accounts.rs. They use fixed fixtures and assert literal values.

  • Card mapping:
    • The pack payload maps to the Mac card: 45% left, reset, both team rows with "Bob Pro", and the "API key" identity.
    • A team without a limit makes the total usage-only.
    • A zero total limit is usage-only, and overspend clamps.
    • Row and plan naming follow upstream, as do team fallbacks and Bobcoin formatting.
  • Parsing:
    • refresh_at accepts seconds and ISO strings.
    • Malformed payloads fail without echoing the body.
  • Credentials:
    • JWT tokens use Bearer, and API keys use Apikey.
    • Keys are trimmed and unquoted, and a quoted blank key counts as missing.
  • Hosts and statuses:
    • Regional hosts must be HTTPS under bob.ibm.com.
    • Path segments are percent-encoded.
    • Status codes map to upstream messages.
  • Local server:
    • The profile is fetched first, then each team's budget.
    • An untrusted region fails before any team request.
    • No usable instance or team gives a no-subscription error.
    • Errors don't echo the body.
    • Web and CLI sources are unsupported.
  • Token accounts: keys inject BOBSHELL_API_KEY.

Commands

Command Result
cargo fmt --all -- --check pass
cargo test --manifest-path rust/Cargo.toml pass (3823 passed, 1 ignored) after adding the ibm bob display-name alias; the first run failed only test_provider_id_from_display_name_aliases
cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings pass (rerun after the alias fix)
cargo test --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml pass (637)
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 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 (5ce549d), made through the parity rig (build-proof.sh). The proof-shim patch is never committed.
  • Capture: win_run.py with the IBMBob scenario pack. It uses a synthetic API key and a mocked api.us-east.bob.ibm.com (the profile and two team budgets, all 200).
  • Files:
    • Windows panel: W:/mac-parity/report/provider-ibmbob/panel.png
    • Mac card: W:/mac-parity/report/provider-ibmbob/mac-card.png
    • comparison: W:/mac-parity/report/provider-ibmbob/COMPARISON.md
  • Result: these all match the Mac card:
    • title, "API key", "Monthly Bobcoins 45% left" and "Resets in 15d"
    • both team rows with their plans
    • the Usage Dashboard and Status Page links
  • Settings API key field: win_run.py --mode settings:providers --target settings on this commit (5ce549d) with a copy of the pack that lists this provider first (W:/mac-parity/report/provider-ibmbob/settings-pack/). The pane shows the "API Key" section with the synthetic key masked as "sk-p...", Update and Remove, and the hint "Create an API key in the IBM Bob web portal and save it here, or set BOBSHELL_API_KEY." W:/mac-parity/report/provider-ibmbob/settings-proof/settings-after.png and .json

Gaps vs the Mac card

  • Pace text: the shared Windows card prints a pace line under the bar ("4% in deficit · Runs out in 12d 12h", "On-pace budget"). The Mac card shows only the tick.
  • Team rows: they render as "Label: value plan" lines rather than Mac's two-column rows with the plan underneath. This is shared card rendering, out of scope here.
  • 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
  • api_keys.rs and token_accounts.rs
  • providerCatalog.ts and the providerIcons.ts registry
  • the docs/PROVIDERS.md section and README table rows

@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 20 minutes.

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: 6e8b0de8-05be-4942-8b3a-af0d8a73db2c

📥 Commits

Reviewing files that changed from the base of the PR and between bb63368 and b90e275.


⛔ Files ignored due to path filters (3)
  • 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-synthetic.svg is excluded by !**/*.svg

📒 Files selected for processing (34)
  • README.md
  • apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs
  • 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/mod.rs
  • rust/src/providers/synthetic/mod.rs
  • rust/src/providers/synthetic/tests.rs
  • rust/src/settings/api_keys.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.

# 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
- 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.
- 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.
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