Skip to content

Add Venice API balance provider#865

Merged
steipete merged 10 commits intosteipete:mainfrom
clawSean:feat/venice-usage-provider
May 10, 2026
Merged

Add Venice API balance provider#865
steipete merged 10 commits intosteipete:mainfrom
clawSean:feat/venice-usage-provider

Conversation

@clawSean
Copy link
Copy Markdown
Contributor

@clawSean clawSean commented May 8, 2026

Add Venice API balance provider

Summary

This PR adds Venice as a first-class CodexBar provider, enabling users to monitor their Venice API balance (DIEM or USD) directly from the menu bar.

Scope: Stable balance endpoint only (GET /api/v1/billing/balance). No beta history or usage-analytics endpoints in this PR.

Changes

Core provider setup

  • Added .venice case to UsageProvider and IconStyle enums
  • Created VeniceProviderDescriptor with macro registration and fetch strategy
  • Created VeniceSettingsReader for env key resolution (VENICE_API_KEY / VENICE_KEY)

API integration

  • Implemented VeniceUsageFetcher for /api/v1/billing/balance endpoint with bearer auth (15s timeout)
  • Decoded response: canConsume, consumptionCurrency, balances.diem, balances.usd, diemEpochAllocation
  • Honest balance display: no fake quota percentages unless DIEM epoch allocation is present
  • Balance display copy: "DIEM 90.50 / 100.00 epoch allocation" or "$25.00 USD remaining" or "Balance unavailable"

Token & settings integration

  • Added veniceToken() and veniceResolution() to ProviderTokenResolver
  • Added Venice to TokenAccountSupportCatalog+Data with environment injection
  • Added veniceUsage log category
  • Updated ProviderConfigEnvironment for API key injection

App-side implementation

  • Created VeniceProviderImplementation following DeepSeek pattern (available when key exists or token accounts exist)

Testing

  • VeniceSettingsReaderTests: 10 tests covering env key resolution, quoting, trimming, and precedence
  • VeniceUsageFetcherTests: 19 tests covering DIEM/USD parsing, epoch allocation, canConsume=false, edge cases, and error handling

Documentation

  • Created docs/venice.md with setup instructions, balance types, and troubleshooting
  • Updated README.md to include Venice in provider list
  • Updated docs/providers.md with Venice details and API endpoint info

Implementation notes

  • Provider identity is siloed to Venice (no sharing with OpenRouter/Codex/others)
  • Balance display uses RateWindow with honest remaining amounts (prefers DIEM with allocation percentage when available; USD or DIEM remaining otherwise)
  • No real API keys, account data, screenshots, or local paths included
  • Follows CodexBar AGENTS.md contribution guidelines and existing provider patterns (DeepSeek/OpenRouter)

Testing

Run locally (on macOS):

swift test --filter Venice
swift test --filter ProviderRegistry
swift test
pnpm check
swiftformat Sources Tests
swiftlint --strict

Dashboard & Setup

  • Venice API settings: https://venice.ai/settings/api
  • Env keys: VENICE_API_KEY (primary), VENICE_KEY (fallback)
  • Endpoint: https://api.venice.ai/api/v1/billing/balance (stable, v1)

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b14d485f73

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

case mistral
case deepseek
case codebuff
case venice
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update exhaustive provider switches for Venice

Adding the .venice enum case makes every exhaustive switch UsageProvider require a Venice branch. I checked Sources/CodexBar/Providers/Shared/ProviderImplementationRegistry.swift and the widget switches in Sources/CodexBarWidget/CodexBarWidgetProvider.swift / CodexBarWidgetViews.swift; they still stop at .codebuff with no default, so the app/widget targets will fail to compile as soon as this case is introduced.

Useful? React with 👍 / 👎.

if !self.canConsume {
balanceDetail = "Balance unavailable for API calls"
usedPercent = 100
} else if let diem = self.diemBalance, let allocation = self.diemEpochAllocation, allocation > 0 {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the active Venice consumption currency

When the balance response contains both DIEM and USD but consumptionCurrency is USD, this branch still reports DIEM first and can show DIEM allocation progress even though Venice says API calls will consume USD. Since the API includes consumptionCurrency specifically to identify the active billing currency, users with both balances can see the wrong remaining balance in the menu bar.

Useful? React with 👍 / 👎.

@clawSean
Copy link
Copy Markdown
Contributor Author

clawSean commented May 8, 2026

Clean follow-up (previous comment had shell-escaped markdown issues):

Addressed both review items in commit 1c7c3d2.

  1. Exhaustive switch coverage for new Venice provider:
  • Sources/CodexBar/Providers/Shared/ProviderImplementationRegistry.swift
  • Sources/CodexBarWidget/CodexBarWidgetProvider.swift
  • Sources/CodexBarWidget/CodexBarWidgetViews.swift (short label + widget color switch)
  1. Active billing currency display:
  • Sources/CodexBarCore/Providers/Venice/VeniceUsageFetcher.swift now honors consumptionCurrency when both DIEM and USD balances are present.
  • Added regression test in Tests/CodexBarTests/VeniceUsageFetcherTests.swift:
    uses USD display when consumptionCurrency is USD and both balances exist

@clawSean
Copy link
Copy Markdown
Contributor Author

clawSean commented May 8, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1c7c3d25ee

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

case mistral
case deepseek
case codebuff
case venice
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add Venice to remaining exhaustive provider switches

Adding a new UsageProvider case requires updating every exhaustive switch; this commit updates several call sites but leaves others, including Sources/CodexBarCLI/TokenAccountCLI.swift:81, Sources/CodexBar/UsageStore.swift:836, and Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift:225, without a .venice branch or default. As soon as the app/CLI targets are built with this enum case, those switches are non-exhaustive and the package cannot compile.

Useful? React with 👍 / 👎.

@clawSean
Copy link
Copy Markdown
Contributor Author

clawSean commented May 8, 2026

Checked — new Codex P1 was valid. Addressed in 0b5d0e90.

Added .venice to the remaining exhaustive UsageProvider switches called out by review:

  • Sources/CodexBarCLI/TokenAccountCLI.swift
  • Sources/CodexBar/UsageStore.swift
  • Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift

Branch is updated and pushed.

@clawSean
Copy link
Copy Markdown
Contributor Author

clawSean commented May 8, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0b5d0e901f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

private static func parseSnapshot(data: Data) throws -> VeniceUsageSnapshot {
let decoded: VeniceBalanceResponse
do {
decoded = try JSONDecoder().decode(VeniceBalanceResponse.self, from: data)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept string-encoded Venice balances

When Venice returns balance numbers as JSON strings, this strict decode into Double? fields fails and the provider reports parseFailed instead of showing the balance. Venice’s API docs note that numeric balance values may be returned as strings to avoid precision loss (https://docs.venice.ai/api-reference/api-spec), so the balance response should decode both numeric and string forms for balances and diemEpochAllocation.

Useful? React with 👍 / 👎.

@clawSean
Copy link
Copy Markdown
Contributor Author

clawSean commented May 8, 2026

Status update: a new Codex P2 landed (Accept string-encoded Venice balances).

Fixed in 2b506fda:

  • VeniceBalanceResponse + VeniceBalances now decode numeric fields from either JSON number or numeric string.
  • Added regression test: parses string-encoded balances and allocation.

Branch pushed and ready for re-review.

@clawSean
Copy link
Copy Markdown
Contributor Author

clawSean commented May 8, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2b506fdaf6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

let usdStr = String(format: "%.2f", usd)
balanceDetail = "$\(usdStr) USD remaining"
usedPercent = 0
} else if activeCurrency == "DIEM", let diem = self.diemBalance, let allocation = self.diemEpochAllocation, allocation > 0 {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle bundled-credit DIEM allocations

For accounts where Venice returns consumptionCurrency: "BUNDLED_CREDITS" with balances.diem and diemEpochAllocation (a documented response shape), this condition is skipped because it only accepts DIEM; the code then falls through to the generic DIEM balance branch and reports usedPercent = 0 instead of the allocation progress. This makes staked/bundled-credit accounts with partial usage look completely unused in the menu bar.

Useful? React with 👍 / 👎.

@clawSean
Copy link
Copy Markdown
Contributor Author

clawSean commented May 8, 2026

Checked now — latest Codex P2 was valid (Handle bundled-credit DIEM allocations).

Fixed in 4abdf58b:

  • Treat non-USD consumption currencies (including BUNDLED_CREDITS) with diemEpochAllocation as DIEM allocation progress.
  • Added regression test: uses DIEM allocation progress for bundled credits currency.

Branch pushed.

@clawSean
Copy link
Copy Markdown
Contributor Author

clawSean commented May 9, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

clawSean and others added 8 commits May 10, 2026 02:07
- Add Venice as first-class UsageProvider with .venice enum case
- Implement VeniceSettingsReader for VENICE_API_KEY / VENICE_KEY env resolution
- Implement VeniceUsageFetcher for GET /api/v1/billing/balance endpoint
- Add VeniceProviderDescriptor with macro registration and API fetch strategy
- Add token account support in TokenAccountSupportCatalog+Data
- Add config environment injection in ProviderConfigEnvironment
- Implement VeniceProviderImplementation for menu bar integration
- Add VeniceSettingsReaderTests with env key resolution coverage
- Add VeniceUsageFetcherTests with DIEM/USD/epoch allocation scenarios
- Display honest balance (no fake quota %)
- Add docs/venice.md and update README / providers documentation

API: stable /api/v1/billing/balance endpoint only (no beta history endpoints)
Scope: balance display with canConsume flag and optional epoch allocation
Dashboard: https://venice.ai/settings/api
@steipete steipete force-pushed the feat/venice-usage-provider branch from 4abdf58 to 48f3474 Compare May 10, 2026 01:26
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48f34749ab

ℹ️ 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".

Comment on lines +134 to +136
Self.scheduleAppGroupMigration()
appGroupMigration = AppGroupSupport.MigrationResult(status: .targetUnavailable)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Run app-group migration before reading settings

Calling scheduleAppGroupMigration() here makes migration asynchronous, but loadDefaultsState runs immediately afterward and reads defaults before legacy app-group keys are copied. On first launch after upgrade, users who only have legacy values (e.g. debugDisableKeychainAccess / widgetSelectedProvider) will run with stale settings until a restart, because this initializer never reloads defaults after the detached task finishes.

Useful? React with 👍 / 👎.

Comment on lines +219 to +221
if try self.decodeNil(forKey: key) {
return nil
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat omitted Venice balance fields as optional

decodeFlexibleDoubleIfPresent begins with decodeNil(forKey:), which throws keyNotFound when the key is absent, so these optional numeric fields become effectively required. If Venice omits diem, usd, or diemEpochAllocation (instead of sending explicit null), parsing fails and the provider reports parseFailed for an otherwise valid response.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner

@steipete steipete left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed provider wiring, decoder behavior, token-account/env routing, Linux compatibility, and live app smoke. Local + CI green.

@steipete steipete merged commit bf1472e into steipete:main May 10, 2026
4 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.

2 participants