Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import AppKit
import CodexBarCore
import CodexBarMacroSupport
import Foundation
import SwiftUI

@ProviderImplementationRegistration
struct CheapestInferenceProviderImplementation: ProviderImplementation {
let id: UsageProvider = .cheapestinference

@MainActor
func presentation(context _: ProviderPresentationContext) -> ProviderPresentation {
ProviderPresentation { _ in "api" }
}

@MainActor
func observeSettings(_ settings: SettingsStore) {
_ = settings.cheapestInferenceAPIToken
}

@MainActor
func settingsSnapshot(context: ProviderSettingsSnapshotContext) -> ProviderSettingsSnapshotContribution? {
_ = context
return nil
}

@MainActor
func isAvailable(context: ProviderAvailabilityContext) -> Bool {
if CheapestInferenceSettingsReader.apiToken(environment: context.environment) != nil {
return true
}
return !context.settings.cheapestInferenceAPIToken
.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}

@MainActor
func settingsPickers(context _: ProviderSettingsContext) -> [ProviderSettingsPickerDescriptor] {
[]
}

@MainActor
func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
[
ProviderSettingsFieldDescriptor(
id: "cheapestinference-api-key",
title: "API key",
subtitle: "Stored in ~/.codexbar/config.json. "
+ "Get your key from cheapestinference.com/dashboard.",
kind: .secure,
placeholder: "sk-...",
binding: context.stringBinding(\.cheapestInferenceAPIToken),
actions: [],
isVisible: nil,
onActivate: nil),
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import CodexBarCore
import Foundation

extension SettingsStore {
var cheapestInferenceAPIToken: String {
get { self.configSnapshot.providerConfig(for: .cheapestinference)?.sanitizedAPIKey ?? "" }
set {
self.updateProviderConfig(provider: .cheapestinference) { entry in
entry.apiKey = self.normalizedConfigValue(newValue)
}
self.logSecretUpdate(provider: .cheapestinference, field: "apiKey", value: newValue)
}
}
}
6 changes: 6 additions & 0 deletions Sources/CodexBar/Resources/ProviderIcon-cheapestinference.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions Sources/CodexBarCore/Logging/LogCategories.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public enum LogCategories {
public static let ollama = "ollama"
public static let opencodeUsage = "opencode-usage"
public static let openRouterUsage = "openrouter-usage"
public static let cheapestInferenceUsage = "cheapestinference-usage"
public static let providerDetection = "provider-detection"
public static let providers = "providers"
public static let sessionQuota = "sessionQuota"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import CodexBarMacroSupport
import Foundation

@ProviderDescriptorRegistration
@ProviderDescriptorDefinition
public enum CheapestInferenceProviderDescriptor {
static func makeDescriptor() -> ProviderDescriptor {
ProviderDescriptor(
id: .cheapestinference,
metadata: ProviderMetadata(
id: .cheapestinference,
displayName: "CheapestInference",
sessionLabel: "Budget",
weeklyLabel: "Usage",
opusLabel: nil,
supportsOpus: false,
supportsCredits: true,
creditsHint: "Budget utilization from CheapestInference API",
toggleTitle: "Show CheapestInference usage",
cliName: "cheapestinference",
defaultEnabled: false,
isPrimaryProvider: false,
usesAccountFallback: false,
dashboardURL: "https://cheapestinference.com/dashboard",
statusPageURL: nil),
branding: ProviderBranding(
iconStyle: .cheapestinference,
iconResourceName: "ProviderIcon-cheapestinference",
color: ProviderColor(red: 16 / 255, green: 185 / 255, blue: 129 / 255)),
tokenCost: ProviderTokenCostConfig(
supportsTokenCost: false,
noDataMessage: { "CheapestInference cost summary is not yet supported." }),
fetchPlan: ProviderFetchPlan(
sourceModes: [.auto, .api],
pipeline: ProviderFetchPipeline(resolveStrategies: { _ in
[CheapestInferenceAPIFetchStrategy()]
})),
cli: ProviderCLIConfig(
name: "cheapestinference",
aliases: ["ci"],
versionDetector: nil))
}
}

struct CheapestInferenceAPIFetchStrategy: ProviderFetchStrategy {
let id: String = "cheapestinference.api"
let kind: ProviderFetchKind = .apiToken

func isAvailable(_ context: ProviderFetchContext) async -> Bool {
Self.resolveToken(environment: context.env) != nil
}

func fetch(_ context: ProviderFetchContext) async throws -> ProviderFetchResult {
guard let apiKey = Self.resolveToken(environment: context.env) else {
throw CheapestInferenceSettingsError.missingToken
}
let usage = try await CheapestInferenceUsageFetcher.fetchUsage(
apiKey: apiKey,
environment: context.env)
return self.makeResult(
usage: usage.toUsageSnapshot(),
sourceLabel: "api")
}

func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool {
false
}

private static func resolveToken(environment: [String: String]) -> String? {
ProviderTokenResolver.cheapestInferenceToken(environment: environment)
}
}

/// Errors related to CheapestInference settings
public enum CheapestInferenceSettingsError: LocalizedError, Sendable {
case missingToken

public var errorDescription: String? {
switch self {
case .missingToken:
"CheapestInference API token not configured. Set CHEAPESTINFERENCE_API_KEY environment variable or configure in Settings."
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Foundation

/// Reads CheapestInference settings from environment variables
public enum CheapestInferenceSettingsReader {
/// Environment variable key for CheapestInference API token
public static let envKey = "CHEAPESTINFERENCE_API_KEY"

/// Returns the API token from environment if present and non-empty
public static func apiToken(environment: [String: String] = ProcessInfo.processInfo.environment) -> String? {
self.cleaned(environment[self.envKey])
}

/// Returns the API URL, defaulting to production endpoint
public static func apiURL(environment: [String: String] = ProcessInfo.processInfo.environment) -> URL {
if let override = environment["CHEAPESTINFERENCE_API_URL"],
let url = URL(string: cleaned(override) ?? "")
{
return url
}
return URL(string: "https://api.cheapestinference.com")!
}

static func cleaned(_ raw: String?) -> String? {
guard var value = raw?.trimmingCharacters(in: .whitespacesAndNewlines), !value.isEmpty else {
return nil
}

if (value.hasPrefix("\"") && value.hasSuffix("\"")) ||
(value.hasPrefix("'") && value.hasSuffix("'"))
{
value.removeFirst()
value.removeLast()
}

value = value.trimmingCharacters(in: .whitespacesAndNewlines)
return value.isEmpty ? nil : value
}
}
Loading