Skip to content

feat(provider): add Mistral (Vibe CLI + Studio) as a provider (#205) - #206

Closed
hyptos wants to merge 2 commits into
CodeZeno:mainfrom
hyptos:feat/205/mistral-provider
Closed

hyptos wants to merge 2 commits into
CodeZeno:mainfrom
hyptos:feat/205/mistral-provider

Conversation

@hyptos

@hyptos hyptos commented Nov 3, 2026 •

Copy link
Copy Markdown

Summary

Implements the new Mistral provider requested in #205, covering both the Vibe CLI and Mistral Studio (La Plateforme console) with one API key.

  • Credentials: MISTRAL_API_KEY environment variable first, then a mistral:vibe-api-key generic credential in Windows Credential Manager — the secret never lands in settings.json. Keys are header-safety-checked and only ever logged as hashes (credential watch).
  • Session row: x-ratelimit-* headers from GET https://api.mistral.ai/v1/models (requests, falling back to tokens), with x-ratelimit-reset-* parsed as seconds or a duration string for the reset time.
  • Long row (labelled 30d): calendar-month spend in EUR summed from GET /v1/billing/usage (data[].total_cost, filtered to entries overlapping the current UTC month), measured against monthly_budget from GET /v1/billing/subscription; resets at midnight UTC on the 1st. Billing routes the key cannot read (403/404) are skipped so the rate-limit window still shows.
  • Wiring: ProviderId::Mistral descriptor (key mistral, native menu command 69), poller registration in PROVIDER_POLLERS, show_mistral settings key, classic context-menu entry, translations for all 14 bundled locales, brand mark at U+F008 in brand-marks.ttf (Mistral AI mark from Simple Icons, CC0-1.0, geometry per the documented 958-unit convention), and Mistral layers cloned into the three bundled themes with Mistral orange accents (tray fill, pool segments, vertical titles with >= 4.5:1 contrast).
  • Tests: unit tests in src/poller/mistral.rs for month-boundary spend summing, budget percentage and year-wrapping reset, rate-limit header mapping, reset-duration parsing, key header-safety, and the civil-date algorithms. Existing exhaustive matches (ProviderId::ALL arms in poller/theme tests, settings round-trip, context-menu contents, vertical-theme height rule) were updated.

Testing

  • Tests were not run. cargo test --locked requires a Windows host (the crate targets Win32/MSVC) and none was available for this change — please run the test suite on Windows or let CI do it before merging.
  • cargo build --locked --release and the Windows VM scripts (tests/windows-vm) were not run either; they also need a real Windows host.
  • Checks that could run here (Linux, cross-compiled to x86_64-pc-windows-gnu): cargo fmt --all -- --check, cargo check --all-targets --locked, cargo clippy --all-targets --locked, cargo audit --file Cargo.lock, cargo deny --locked check — all clean, no new warnings.
  • Static consistency checks done by hand: replicated the build.rs locale validation in Python across all 14 locales (key parity, non-empty values, placeholder parity — passes); themes revalidated as JSON with the copilot layers byte-identical to HEAD and every mistral.* binding matching the copilot binding set; all exhaustive matches on ProviderId audited by grep; brand-mark font re-parsed with fontTools (cmap U+F008 -> uniF008, advance 1000, non-blank outline).
  • No credentials, tokens, or account data included anywhere in the diff.

Checklist

  • I have read CONTRIBUTING.md and CODE_OF_CONDUCT.md.
  • The change is focused and contains no credentials or sensitive data.
  • I have added or updated relevant documentation and tests, where applicable.
  • I have left changelog and version changes to maintainers unless requested.

…no#205)

New `mistral` provider polling api.mistral.ai for both the Vibe CLI and
Mistral Studio (La Plateforme):

- Credentials: MISTRAL_API_KEY environment variable, then the
  `mistral:vibe-api-key` generic credential in Windows Credential Manager.
- Session row: x-ratelimit-* headers from GET /v1/models.
- Long row: calendar-month spend in EUR from GET /v1/billing/usage against
  monthly_budget from GET /v1/billing/subscription, labelled 30d and resetting
  at midnight UTC on the 1st. Billing routes the key cannot read (403/404)
  are skipped without failing the poll.
- Wiring: provider descriptor (native menu command 69), poller registration,
  show_mistral setting key, context-menu entry, translations for the 14
  bundled locales, brand mark at U+F008 in brand-marks.ttf (Simple Icons,
  CC0-1.0), and Mistral layers in the three bundled themes.

Checks not run here: cargo fmt/test/build require Windows. The build.rs
locale validation was replicated in Python (key parity, placeholders), themes
were revalidated as JSON, and every exhaustive match on ProviderId was
audited by grep.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
…pectations (CodeZeno#205)

- Build the UsageData with an early return instead of matching on
  (bool, Option), which did not type-check.
- Drop a u64 -> u64 cast flagged by clippy in days_from_civil.
- Update classic theme expectations for the eighth provider: widget width
  with all providers 725 -> 815, tray-icon surface count 8 -> 9, and the
  long-window-only segment layers 30 -> 32 in the round-trip test.
- Recolour the Mistral tray fill in classic-vertical to the same Mistral
  orange used in the other bundled themes so the tray roots match the
  starter theme.
- Apply cargo fmt.

Verified with cargo fmt --check, cargo check/clippy --target
x86_64-pc-windows-gnu --all-targets, and the full test suite (631 tests)
run under wine: 620 pass; the 5 remaining failures are identical on
unpatched main and are wine environment limits (Segoe UI metrics, shim
execution, window lifecycle, winsqlite3 stub).

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
@hyptos

hyptos commented Nov 3, 2026 •

Copy link
Copy Markdown
Author

Checks run locally (Linux sandbox, cross-compiled to x86_64-pc-windows-gnu, tests executed under wine 9.0 with TZ=UTC):

  • cargo fmt --all -- --check — clean
  • cargo check --target x86_64-pc-windows-gnu --all-targets --locked — clean
  • cargo clippy --target x86_64-pc-windows-gnu --all-targets --locked — no new warnings (1 fixed in this branch; 2 pre-existing on main)
  • cargo audit --file Cargo.lock — ok (1 allowed warning, pre-existing)
  • cargo deny --locked check — advisories/bans/licenses/sources ok
  • cargo test --locked (631 tests, run under wine): 620 passed, 6 ignored, 5 failed — the 5 failures are identical on unpatched main and are wine environment limits (Segoe UI font metrics, .ps1 shim execution, window lifecycle timers, winsqlite3 stub DLL), not regressions. All 7 new poller::mistral tests pass.

Not run here: cargo build --locked --release and the Windows VM test scripts (tests/windows-vm) — those need a real Windows host.

@hyptos

hyptos commented Nov 4, 2026

Copy link
Copy Markdown
Author

Closing this: after probing the live API with a standard Mistral API key, there is no usage data the monitor can read reliably.

Endpoint Result
GET /v1/models 200, but no rate-limit headers
GET /v1/billing/usage 404 (the endpoint does not exist)
GET /v1/billing/subscription 200, but only plan_name, payg_enabled, vibe_payg_enabled, enterprise: no spend or budget
GET /v1/admin/usage 401: needs an Admin API key, which is Enterprise-only
POST /v1/chat/completions per-minute limits only (x-ratelimit-{limit,remaining}-tokens-minute, …-req-minute), and polling it would spend tokens

The remaining options are either the Enterprise-only Admin API (response fields not documented) or the undocumented console endpoint behind a browser session cookie. Neither is a good fit for a provider that should work out of the box, so I'm dropping this rather than shipping a provider that shows nothing.

Happy to revisit if Mistral exposes usage to standard API keys or to the Vibe CLI login.

@hyptos hyptos closed this Nov 4, 2026
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