-
Notifications
You must be signed in to change notification settings - Fork 2.4k
feat: add dynamic model loading for Roo Code Cloud provider #8728
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
4444328
626d97b
382764c
eeabc50
dbdc8e4
b2c02de
b3054a6
26978df
dfecaa0
18aeb4f
d442484
60e900c
b941b65
e78aace
6a1c35e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| ## Summary | ||
|
|
||
| Enables the Roo Code extension to dynamically load available models from the Roo Code Cloud provider via the `/v1/models` endpoint. | ||
|
|
||
| ## Changes | ||
|
|
||
| - **New fetcher**: Added `getRooModels()` function to fetch models from Roo Code Cloud `/v1/models` endpoint | ||
| - **Dynamic provider**: Added "roo" to the list of dynamic providers | ||
| - **Type updates**: Updated RooHandler to support dynamic model IDs (changed from `RooModelId` to `string`) | ||
| - **Model caching**: Integrated with existing modelCache infrastructure for efficient caching | ||
| - **Graceful fallback**: Falls back to static model definitions if dynamic loading fails | ||
|
|
||
| ## Technical Details | ||
|
|
||
| ### Model Loading Strategy | ||
|
|
||
| - Models are loaded asynchronously on handler initialization | ||
| - Dynamic models are merged with static models (static definitions take precedence) | ||
| - Uses 5-minute memory cache + file cache from existing infrastructure | ||
| - 10-second timeout prevents hanging on network issues | ||
|
|
||
| ### Type Safety | ||
|
|
||
| - Maintains backward compatibility with existing static models | ||
| - Generic type changed from `RooModelId` to `string` to support dynamic model IDs | ||
| - All type definitions updated across shared/api.ts and provider-settings.ts | ||
|
|
||
| ## Testing | ||
|
|
||
| - Linting passes | ||
| - Type checks pass | ||
| - Follows patterns from other dynamic providers (requesty, glama, unbound) | ||
| - Error handling with descriptive logging | ||
|
|
||
| ## Related | ||
|
|
||
| This PR works in conjunction with Roo-Code-Cloud PR #1316 which adds the `/v1/models` endpoint. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| import axios from "axios" | ||
|
|
||
| import type { ModelRecord } from "../../../shared/api" | ||
|
|
||
| import { DEFAULT_HEADERS } from "../constants" | ||
|
|
||
| /** | ||
| * Fetches available models from the Roo Code Cloud provider | ||
| * | ||
| * @param baseUrl The base URL of the Roo Code Cloud provider | ||
| * @param apiKey The API key (session token) for the Roo Code Cloud provider | ||
| * @returns A promise that resolves to a record of model IDs to model info | ||
| * @throws Will throw an error if the request fails or the response is not as expected. | ||
| */ | ||
| export async function getRooModels(baseUrl: string, apiKey?: string): Promise<ModelRecord> { | ||
| try { | ||
| const headers: Record<string, string> = { | ||
| "Content-Type": "application/json", | ||
| ...DEFAULT_HEADERS, | ||
| } | ||
|
|
||
| if (apiKey) { | ||
| headers["Authorization"] = `Bearer ${apiKey}` | ||
| } | ||
|
|
||
| // Normalize the URL to ensure proper /v1/models endpoint construction | ||
|
||
| const urlObj = new URL(baseUrl) | ||
| urlObj.pathname = urlObj.pathname.replace(/\/+$/, "").replace(/\/+/g, "/") + "/v1/models" | ||
| const url = urlObj.href | ||
|
|
||
| // Added timeout to prevent indefinite hanging | ||
| const response = await axios.get(url, { headers, timeout: 10000 }) | ||
|
||
| const models: ModelRecord = {} | ||
|
|
||
| // Process the model info from the response | ||
| // Expected format: { object: "list", data: [{ id: string, object: "model", created: number, owned_by: string }] } | ||
| if (response.data && response.data.data && Array.isArray(response.data.data)) { | ||
| for (const model of response.data.data) { | ||
| const modelId = model.id | ||
|
|
||
| if (!modelId) continue | ||
|
|
||
| // For Roo Code Cloud, we provide basic model info | ||
| // The actual detailed model info is stored in the static rooModels definition | ||
| // This just confirms which models are available | ||
| models[modelId] = { | ||
| maxTokens: 16_384, // Default fallback | ||
| contextWindow: 262_144, // Default fallback | ||
| supportsImages: false, | ||
| supportsPromptCache: true, | ||
| inputPrice: 0, | ||
| outputPrice: 0, | ||
| description: `Model available through Roo Code Cloud`, | ||
| } | ||
| } | ||
| } else { | ||
| // If response.data.data is not in the expected format, consider it an error. | ||
| console.error("Error fetching Roo Code Cloud models: Unexpected response format", response.data) | ||
| throw new Error("Failed to fetch Roo Code Cloud models: Unexpected response format.") | ||
| } | ||
|
|
||
| return models | ||
| } catch (error: any) { | ||
| console.error("Error fetching Roo Code Cloud models:", error.message ? error.message : error) | ||
| if (axios.isAxiosError(error) && error.response) { | ||
| throw new Error( | ||
| `Failed to fetch Roo Code Cloud models: ${error.response.status} ${error.response.statusText}. Check base URL and API key.`, | ||
| ) | ||
| } else if (axios.isAxiosError(error) && error.request) { | ||
| throw new Error( | ||
| "Failed to fetch Roo Code Cloud models: No response from server. Check Roo Code Cloud server status and base URL.", | ||
| ) | ||
| } else { | ||
| throw new Error(`Failed to fetch Roo Code Cloud models: ${error.message || "An unknown error occurred."}`) | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.