Browse Source

Show openrouter key balance on the settings page (#1990)

Matt Rubens 9 months ago
parent
commit
0fd0800ba9

+ 5 - 0
.changeset/four-tools-pump.md

@@ -0,0 +1,5 @@
+---
+"roo-cline": patch
+---
+
+Show openrouter key balance on the settings screen

+ 27 - 2
webview-ui/src/components/settings/ApiOptions.tsx

@@ -46,7 +46,7 @@ import {
 	useOpenRouterModelProviders,
 	OPENROUTER_DEFAULT_PROVIDER_NAME,
 } from "@/components/ui/hooks/useOpenRouterModelProviders"
-
+import { useOpenRouterKeyInfo } from "@/components/ui/hooks/useOpenRouterKeyInfo"
 import { MODELS_BY_PROVIDER, PROVIDERS, AWS_REGIONS, VERTEX_REGIONS } from "./constants"
 import { VSCodeButtonLink } from "../common/VSCodeButtonLink"
 import { ModelInfoView } from "./ModelInfoView"
@@ -57,6 +57,23 @@ import { ApiErrorMessage } from "./ApiErrorMessage"
 import { ThinkingBudget } from "./ThinkingBudget"
 import { R1FormatSetting } from "./R1FormatSetting"
 
+// Component to display OpenRouter API key balance
+const OpenRouterBalanceDisplay = ({ apiKey, baseUrl }: { apiKey: string; baseUrl?: string }) => {
+	const { data: keyInfo } = useOpenRouterKeyInfo(apiKey, baseUrl)
+
+	if (!keyInfo || !keyInfo.limit) {
+		return null
+	}
+
+	const formattedBalance = (keyInfo.limit - keyInfo.usage).toFixed(2)
+
+	return (
+		<VSCodeLink href="https://openrouter.ai/settings/keys" className="text-vscode-foreground hover:underline">
+			${formattedBalance}
+		</VSCodeLink>
+	)
+}
+
 interface ApiOptionsProps {
 	uriScheme: string | undefined
 	apiConfiguration: ApiConfiguration
@@ -274,7 +291,15 @@ const ApiOptions = ({
 						onInput={handleInputChange("openRouterApiKey")}
 						placeholder={t("settings:placeholders.apiKey")}
 						className="w-full">
-						<label className="block font-medium mb-1">{t("settings:providers.openRouterApiKey")}</label>
+						<div className="flex justify-between items-center mb-1">
+							<label className="block font-medium">{t("settings:providers.openRouterApiKey")}</label>
+							{apiConfiguration?.openRouterApiKey && (
+								<OpenRouterBalanceDisplay
+									apiKey={apiConfiguration.openRouterApiKey}
+									baseUrl={apiConfiguration.openRouterBaseUrl}
+								/>
+							)}
+						</div>
 					</VSCodeTextField>
 					<div className="text-sm text-vscode-descriptionForeground -mt-2">
 						{t("settings:providers.apiKeyStorageNotice")}

+ 59 - 0
webview-ui/src/components/ui/hooks/useOpenRouterKeyInfo.ts

@@ -0,0 +1,59 @@
+import axios from "axios"
+import { z } from "zod"
+import { useQuery, UseQueryOptions } from "@tanstack/react-query"
+
+// Define schema for OpenRouter key response
+const openRouterKeyInfoSchema = z.object({
+	data: z.object({
+		label: z.string(),
+		usage: z.number(),
+		is_free_tier: z.boolean(),
+		is_provisioning_key: z.boolean(),
+		rate_limit: z.object({
+			requests: z.number(),
+			interval: z.string(),
+		}),
+		limit: z.number().nullable(),
+	}),
+})
+
+export type OpenRouterKeyInfo = z.infer<typeof openRouterKeyInfoSchema>["data"]
+
+async function getOpenRouterKeyInfo(apiKey?: string, baseUrl?: string) {
+	if (!apiKey) return null
+
+	try {
+		// Use the provided base URL or default to OpenRouter's API URL
+		const apiBaseUrl = baseUrl || "https://openrouter.ai/api/v1"
+
+		const keyEndpoint = `${apiBaseUrl}/key`
+
+		const response = await axios.get(keyEndpoint, {
+			headers: {
+				Authorization: `Bearer ${apiKey}`,
+			},
+		})
+
+		const result = openRouterKeyInfoSchema.safeParse(response.data)
+		if (!result.success) {
+			console.error("OpenRouter API key info validation failed:", result.error)
+			return null
+		}
+
+		return result.data.data
+	} catch (error) {
+		console.error("Error fetching OpenRouter key info:", error)
+		return null
+	}
+}
+
+type UseOpenRouterKeyInfoOptions = Omit<UseQueryOptions<OpenRouterKeyInfo | null>, "queryKey" | "queryFn">
+export const useOpenRouterKeyInfo = (apiKey?: string, baseUrl?: string, options?: UseOpenRouterKeyInfoOptions) => {
+	return useQuery<OpenRouterKeyInfo | null>({
+		queryKey: ["openrouter-key-info", apiKey, baseUrl],
+		queryFn: () => getOpenRouterKeyInfo(apiKey, baseUrl),
+		staleTime: 30 * 1000, // 30 seconds
+		enabled: !!apiKey,
+		...options,
+	})
+}