From 1fb34b81fa442c401dc998a4939f8d6b9c66d529 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 26 Mar 2025 11:25:24 -0400 Subject: [PATCH] Show requesty key balance on the settings screen (#1995) --- .changeset/lazy-ducks-hang.md | 5 ++ .../src/components/settings/ApiOptions.tsx | 26 +++++++++- .../components/ui/hooks/useRequestyKeyInfo.ts | 50 +++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 .changeset/lazy-ducks-hang.md create mode 100644 webview-ui/src/components/ui/hooks/useRequestyKeyInfo.ts diff --git a/.changeset/lazy-ducks-hang.md b/.changeset/lazy-ducks-hang.md new file mode 100644 index 0000000000..6d580f0659 --- /dev/null +++ b/.changeset/lazy-ducks-hang.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Show requesty key balance on the settings screen diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 15d22a7b6f..40e329fca3 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -47,6 +47,7 @@ import { OPENROUTER_DEFAULT_PROVIDER_NAME, } from "@/components/ui/hooks/useOpenRouterModelProviders" import { useOpenRouterKeyInfo } from "@/components/ui/hooks/useOpenRouterKeyInfo" +import { useRequestyKeyInfo } from "@/components/ui/hooks/useRequestyKeyInfo" import { MODELS_BY_PROVIDER, PROVIDERS, AWS_REGIONS, VERTEX_REGIONS } from "./constants" import { VSCodeButtonLink } from "../common/VSCodeButtonLink" import { ModelInfoView } from "./ModelInfoView" @@ -74,6 +75,24 @@ const OpenRouterBalanceDisplay = ({ apiKey, baseUrl }: { apiKey: string; baseUrl ) } +const RequestyBalanceDisplay = ({ apiKey }: { apiKey: string }) => { + const { data: keyInfo } = useRequestyKeyInfo(apiKey) + + if (!keyInfo) { + return null + } + + // Parse the balance to a number and format it to 2 decimal places + const balance = parseFloat(keyInfo.org_balance) + const formattedBalance = balance.toFixed(2) + + return ( + + ${formattedBalance} + + ) +} + interface ApiOptionsProps { uriScheme: string | undefined apiConfiguration: ApiConfiguration @@ -427,7 +446,12 @@ const ApiOptions = ({ onInput={handleInputChange("requestyApiKey")} placeholder={t("settings:providers.getRequestyApiKey")} className="w-full"> - +
+ + {apiConfiguration?.requestyApiKey && ( + + )} +
{t("settings:providers.apiKeyStorageNotice")} diff --git a/webview-ui/src/components/ui/hooks/useRequestyKeyInfo.ts b/webview-ui/src/components/ui/hooks/useRequestyKeyInfo.ts new file mode 100644 index 0000000000..e44aa5fcd1 --- /dev/null +++ b/webview-ui/src/components/ui/hooks/useRequestyKeyInfo.ts @@ -0,0 +1,50 @@ +import axios from "axios" +import { z } from "zod" +import { useQuery, UseQueryOptions } from "@tanstack/react-query" + +const requestyKeyInfoSchema = z.object({ + name: z.string(), + monthly_limit: z.string(), + monthly_spend: z.string(), + org_balance: z.string(), + config: z.object({ + aliases: z.record(z.string(), z.any()).optional(), + }), +}) + +export type RequestyKeyInfo = z.infer + +async function getRequestyKeyInfo(apiKey?: string) { + if (!apiKey) return null + + try { + const response = await axios.get("https://api.requesty.ai/x/apikey", { + headers: { + Authorization: `Bearer ${apiKey}`, + "Content-Type": "application/json", + }, + }) + + const result = requestyKeyInfoSchema.safeParse(response.data) + if (!result.success) { + console.error("Requesty API key info validation failed:", result.error) + return null + } + + return result.data + } catch (error) { + console.error("Error fetching Requesty key info:", error) + return null + } +} + +type UseRequestyKeyInfoOptions = Omit, "queryKey" | "queryFn"> +export const useRequestyKeyInfo = (apiKey?: string, options?: UseRequestyKeyInfoOptions) => { + return useQuery({ + queryKey: ["requesty-key-info", apiKey], + queryFn: () => getRequestyKeyInfo(apiKey), + staleTime: 30 * 1000, // 30 seconds + enabled: !!apiKey, + ...options, + }) +}