Skip to content

Commit ad91c38

Browse files
mcowgerChris Hasson
andauthored
Mcowger/virtual provider (#1487)
* Initial selection and settings. * Add usage tracker class, getModel and createMessage passthroughs * Fix uneeded import * Confirmed changing active handler. * consumption tracking * removing debugging statements. * Working rollovers. * Fix unused import * Add use of feature flag * Unused import * Write and commit tests * Update extension state test. * Add changeset * refactor: pre-code review cleanup for virtual provider - Fix typo in provider-settings.ts comment (defintition -> definition) - Remove debug console logging from virtual.ts (11 statements) - Replace 'any' type with proper 'Event' type in Virtual.tsx - Improve type safety and code cleanliness * refactor: remove virtualQuotaFallbackProvider experiment The virtualQuotaFallbackProvider experiment has been removed. The functionality is now always available and no longer controlled by an experiment flag. This commit removes all references to `virtualQuotaFallbackProvider` from experiment definitions, configurations, and related tests. The `ApiOptions` component in the webview UI has been updated to reflect that the virtual quota fallback provider is always available. * Final cleanup changes * refactor(virtual-quota-fallback): Rename providers to profiles Renames all instances of "provider" to "profile" within the virtual quota fallback system. This includes: - Renaming `providers` array to `profiles` in configuration and types. - Updating variable names like `providerId` to `profileId` and `providerLimits` to `profileLimits`. - Adjusting related test cases and internal logic to reflect the new terminology. This change improves clarity and consistency by aligning the terminology with the concept of managing API profiles rather than generic providers. * refactor(ui): streamline profile manipulation in virtual quota fallback Refactor `VirtualQuotaFallbackProvider` to introduce a `swapProfiles` utility function. This change simplifies the `moveProfileUp` and `moveProfileDown` callbacks by abstracting the profile array manipulation logic. Also, removed redundant comments to improve code readability. * final * Fix strings provider -> profile --------- Co-authored-by: Chris Hasson <[email protected]>
1 parent 6f5c825 commit ad91c38

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1919
-47
lines changed

.changeset/brave-snakes-find.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"kilo-code": minor
3+
"@roo-code/types": patch
4+
---
5+
6+
Introduce a new Virtual Quota Fallback Provider - delegate to other Profiles based on cost or request count limits!
7+
8+
This new virtual provider lets you set cost- or request-based quotas for a list of profiles. It will automatically falls back to the next profile's provider when any limit is reached!
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// kilocode_change - new file
2+
import type { Meta, StoryObj } from "@storybook/react-vite"
3+
import { fn } from "storybook/test"
4+
import { VirtualQuotaFallbackProvider } from "../../../webview-ui/src/components/settings/providers/VirtualQuotaFallbackProvider"
5+
import type { ProviderSettings, ProviderSettingsEntry } from "../../../packages/types/src/provider-settings"
6+
import { withExtensionState } from "../src/decorators/withExtensionState"
7+
8+
const meta = {
9+
title: "Settings/Providers/VirtualQuotaFallbackProvider",
10+
component: VirtualQuotaFallbackProvider,
11+
parameters: {
12+
layout: "padded",
13+
docs: {
14+
description: {
15+
component:
16+
"Virtual Quota Fallback Provider settings component that allows configuring multiple providers with quota limits and automatic fallback.",
17+
},
18+
},
19+
extensionState: {
20+
listApiConfigMeta: [
21+
{
22+
id: "anthropic-1",
23+
name: "Anthropic Claude",
24+
apiProvider: "anthropic" as const,
25+
},
26+
{
27+
id: "openai-1",
28+
name: "OpenAI GPT-4",
29+
apiProvider: "openai" as const,
30+
},
31+
{
32+
id: "gemini-1",
33+
name: "Google Gemini",
34+
apiProvider: "gemini" as const,
35+
},
36+
{
37+
id: "virtual-1",
38+
name: "Virtual Quota Fallback Provider",
39+
apiProvider: "virtual-quota-fallback" as const,
40+
},
41+
{
42+
id: "current-profile",
43+
name: "Current Profile",
44+
apiProvider: "openrouter" as const,
45+
},
46+
] as ProviderSettingsEntry[],
47+
currentApiConfigName: "Current Profile",
48+
},
49+
},
50+
tags: ["autodocs"],
51+
argTypes: {
52+
apiConfiguration: {
53+
description: "Provider configuration object containing virtual provider settings",
54+
control: { type: "object" },
55+
},
56+
setApiConfigurationField: {
57+
description: "Function to update provider configuration fields",
58+
action: "setApiConfigurationField",
59+
},
60+
},
61+
args: {
62+
setApiConfigurationField: fn(),
63+
},
64+
decorators: [withExtensionState],
65+
} satisfies Meta<typeof VirtualQuotaFallbackProvider>
66+
67+
export default meta
68+
type Story = StoryObj<typeof meta>
69+
70+
export const Default: Story = {
71+
args: {
72+
apiConfiguration: {
73+
apiProvider: "virtual-quota-fallback",
74+
profiles: [],
75+
} as ProviderSettings,
76+
},
77+
}
78+
79+
export const WithQuotas: Story = {
80+
args: {
81+
apiConfiguration: {
82+
apiProvider: "virtual-quota-fallback",
83+
profiles: [
84+
{
85+
profileId: "anthropic-1",
86+
profileName: "Anthropic Claude",
87+
profileLimits: {
88+
tokensPerMinute: 100,
89+
tokensPerHour: 5000,
90+
tokensPerDay: 50000,
91+
requestsPerMinute: 2,
92+
requestsPerHour: 50,
93+
requestsPerDay: 500,
94+
},
95+
},
96+
{
97+
profileId: "openai-1",
98+
profileName: "OpenAI GPT-4",
99+
profileLimits: {
100+
tokensPerMinute: 150,
101+
tokensPerHour: 7500,
102+
tokensPerDay: 75000,
103+
requestsPerMinute: 3,
104+
requestsPerHour: 75,
105+
requestsPerDay: 750,
106+
},
107+
},
108+
],
109+
} as ProviderSettings,
110+
},
111+
}
112+
113+
export const NoAvailableProviders: Story = {
114+
args: {
115+
apiConfiguration: {
116+
apiProvider: "virtual-quota-fallback",
117+
profiles: [],
118+
} as ProviderSettings,
119+
},
120+
parameters: {
121+
extensionState: {
122+
listApiConfigMeta: [
123+
{
124+
id: "virtual-1",
125+
name: "Virtual Quota Fallback Provider",
126+
apiProvider: "virtual-quota-fallback" as const,
127+
},
128+
{
129+
id: "current-profile",
130+
name: "Current Profile",
131+
apiProvider: "openrouter" as const,
132+
},
133+
] as ProviderSettingsEntry[],
134+
currentApiConfigName: "Current Profile",
135+
},
136+
},
137+
}

packages/types/src/provider-settings.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export const providerNames = [
3434
"fireworks", // kilocode_change
3535
"kilocode", // kilocode_change
3636
"cerebras", // kilocode_change
37+
"virtual-quota-fallback", // kilocode_change
3738
] as const
3839

3940
export const providerNamesSchema = z.enum(providerNames)
@@ -239,16 +240,31 @@ const kilocodeSchema = baseProviderSettingsSchema.extend({
239240
kilocodeModel: z.string().optional(),
240241
openRouterSpecificProvider: z.string().optional(),
241242
})
242-
243243
const fireworksSchema = baseProviderSettingsSchema.extend({
244244
fireworksModelId: z.string().optional(),
245245
fireworksApiKey: z.string().optional(),
246246
})
247-
248247
const cerebrasSchema = baseProviderSettingsSchema.extend({
249248
cerebrasApiKey: z.string().optional(),
250249
cerebrasModelId: z.string().optional(),
251250
})
251+
export const virtualQuotaFallbackProfileDataSchema = z.object({
252+
profileName: z.string().optional(),
253+
profileId: z.string().optional(),
254+
profileLimits: z
255+
.object({
256+
tokensPerMinute: z.coerce.number().optional(),
257+
tokensPerHour: z.coerce.number().optional(),
258+
tokensPerDay: z.coerce.number().optional(),
259+
requestsPerMinute: z.coerce.number().optional(),
260+
requestsPerHour: z.coerce.number().optional(),
261+
requestsPerDay: z.coerce.number().optional(),
262+
})
263+
.optional(),
264+
})
265+
const virtualQuotaFallbackSchema = baseProviderSettingsSchema.extend({
266+
profiles: z.array(virtualQuotaFallbackProfileDataSchema).optional(),
267+
})
252268
// kilocode_change end
253269

254270
const defaultSchema = z.object({
@@ -282,6 +298,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv
282298
kilocodeSchema.merge(z.object({ apiProvider: z.literal("kilocode") })), // kilocode_change
283299
fireworksSchema.merge(z.object({ apiProvider: z.literal("fireworks") })), // kilocode_change
284300
cerebrasSchema.merge(z.object({ apiProvider: z.literal("cerebras") })), // kilocode_change
301+
virtualQuotaFallbackSchema.merge(z.object({ apiProvider: z.literal("virtual-quota-fallback") })), // kilocode_change
285302
defaultSchema,
286303
])
287304

@@ -314,6 +331,7 @@ export const providerSettingsSchema = z.object({
314331
...kilocodeSchema.shape, // kilocode_change
315332
...fireworksSchema.shape, // kilocode_change
316333
...cerebrasSchema.shape, // kilocode_change
334+
...virtualQuotaFallbackSchema.shape, // kilocode_change
317335
})
318336

319337
export type ProviderSettings = z.infer<typeof providerSettingsSchema>

src/api/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
ChutesHandler,
3030
LiteLLMHandler,
3131
CerebrasHandler, // kilocode_change
32+
VirtualQuotaFallbackHandler, // kilocode_change
3233
ClaudeCodeHandler,
3334
} from "./providers"
3435
// kilocode_change start
@@ -114,6 +115,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler {
114115
// kilocode_change start
115116
case "fireworks":
116117
return new FireworksHandler(options)
118+
case "virtual-quota-fallback":
119+
return new VirtualQuotaFallbackHandler(options)
117120
// kilocode_change end
118121
case "fake-ai":
119122
return new FakeAIHandler(options)

0 commit comments

Comments
 (0)