mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
feat(cli): add LiteLLM as a first-class provider
- Add "litellm" to supportedProviders in types.ts - Add litellmBaseUrl to FlagOptions type - Add LITELLM_API_KEY to environment variable mapping - Add litellm case to getProviderSettings function - Add --litellm-base-url CLI flag with default http://localhost:4000 - Add litellmBaseUrl to ExtensionHostOptions interface - Add support for LITELLM_BASE_URL environment variable - Add tests for LiteLLM provider functionality - Update README with LiteLLM documentation Closes #10839
This commit is contained in:
parent
1a1827d806
commit
103d436a42
7 changed files with 84 additions and 3 deletions
|
|
@ -156,12 +156,13 @@ Tokens are valid for 90 days. The CLI will prompt you to re-authenticate when yo
|
|||
| `-x, --exit-on-complete` | Exit the process when task completes (useful for testing) | `false` |
|
||||
| `-y, --yes` | Non-interactive mode: auto-approve all actions | `false` |
|
||||
| `-k, --api-key <key>` | API key for the LLM provider | From env var |
|
||||
| `-p, --provider <provider>` | API provider (anthropic, openai, openrouter, etc.) | `openrouter` |
|
||||
| `-p, --provider <provider>` | API provider (anthropic, openai, openrouter, litellm, etc.) | `openrouter` |
|
||||
| `-m, --model <model>` | Model to use | `anthropic/claude-sonnet-4.5` |
|
||||
| `-M, --mode <mode>` | Mode to start in (code, architect, ask, debug, etc.) | `code` |
|
||||
| `-r, --reasoning-effort <effort>` | Reasoning effort level (unspecified, disabled, none, minimal, low, medium, high, xhigh) | `medium` |
|
||||
| `--ephemeral` | Run without persisting state (uses temporary storage) | `false` |
|
||||
| `--no-tui` | Disable TUI, use plain text output | `false` |
|
||||
| `--litellm-base-url <url>` | Base URL for LiteLLM endpoint | `http://localhost:4000` |
|
||||
|
||||
## Auth Commands
|
||||
|
||||
|
|
@ -181,8 +182,16 @@ The CLI will look for API keys in environment variables if not provided via `--a
|
|||
| openai | `OPENAI_API_KEY` |
|
||||
| openrouter | `OPENROUTER_API_KEY` |
|
||||
| google/gemini | `GOOGLE_API_KEY` |
|
||||
| litellm | `LITELLM_API_KEY` |
|
||||
| ... | ... |
|
||||
|
||||
**LiteLLM Environment Variables:**
|
||||
|
||||
| Variable | Description |
|
||||
| ------------------ | ---------------------------------------------------------------- |
|
||||
| `LITELLM_API_KEY` | API key for LiteLLM |
|
||||
| `LITELLM_BASE_URL` | Base URL for LiteLLM endpoint (default: `http://localhost:4000`) |
|
||||
|
||||
**Authentication Environment Variables:**
|
||||
|
||||
| Variable | Description |
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ export interface ExtensionHostOptions {
|
|||
* running in an integration test and we want to see the output.
|
||||
*/
|
||||
integrationTest?: boolean
|
||||
/**
|
||||
* Base URL for LiteLLM endpoint (only used when provider is "litellm").
|
||||
*/
|
||||
litellmBaseUrl?: string
|
||||
}
|
||||
|
||||
interface ExtensionModule {
|
||||
|
|
@ -191,7 +195,12 @@ export class ExtensionHost extends EventEmitter implements ExtensionHostInterfac
|
|||
commandExecutionTimeout: 30,
|
||||
browserToolEnabled: false,
|
||||
enableCheckpoints: false,
|
||||
...getProviderSettings(this.options.provider, this.options.apiKey, this.options.model),
|
||||
...getProviderSettings(
|
||||
this.options.provider,
|
||||
this.options.apiKey,
|
||||
this.options.model,
|
||||
this.options.litellmBaseUrl,
|
||||
),
|
||||
}
|
||||
|
||||
this.initialSettings = this.options.nonInteractive
|
||||
|
|
|
|||
|
|
@ -69,6 +69,12 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption
|
|||
flagOptions.yes || flagOptions.dangerouslySkipPermissions || settings.dangerouslySkipPermissions || false
|
||||
const effectiveExitOnComplete = flagOptions.print || flagOptions.oneshot || settings.oneshot || false
|
||||
|
||||
// Determine effective LiteLLM base URL: CLI flag > env var > default (when using litellm provider)
|
||||
let effectiveLitellmBaseUrl: string | undefined = flagOptions.litellmBaseUrl || process.env.LITELLM_BASE_URL
|
||||
if (effectiveProvider === "litellm" && !effectiveLitellmBaseUrl) {
|
||||
effectiveLitellmBaseUrl = "http://localhost:4000"
|
||||
}
|
||||
|
||||
const extensionHostOptions: ExtensionHostOptions = {
|
||||
mode: effectiveMode,
|
||||
reasoningEffort: effectiveReasoningEffort === "unspecified" ? undefined : effectiveReasoningEffort,
|
||||
|
|
@ -81,6 +87,7 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption
|
|||
ephemeral: flagOptions.ephemeral,
|
||||
debug: flagOptions.debug,
|
||||
exitOnComplete: effectiveExitOnComplete,
|
||||
litellmBaseUrl: effectiveLitellmBaseUrl,
|
||||
}
|
||||
|
||||
// Roo Code Cloud Authentication
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ program
|
|||
'Output format (only works with --print): "text" (default), "json" (single result), or "stream-json" (realtime streaming)',
|
||||
"text",
|
||||
)
|
||||
.option(
|
||||
"--litellm-base-url <url>",
|
||||
"Base URL for LiteLLM endpoint (default: http://localhost:4000 when using litellm provider)",
|
||||
)
|
||||
.action(run)
|
||||
|
||||
const authCommand = program.command("auth").description("Manage authentication for Roo Code Cloud")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { getApiKeyFromEnv } from "../provider.js"
|
||||
import { getApiKeyFromEnv, getProviderSettings } from "../provider.js"
|
||||
|
||||
describe("getApiKeyFromEnv", () => {
|
||||
const originalEnv = process.env
|
||||
|
|
@ -27,8 +27,51 @@ describe("getApiKeyFromEnv", () => {
|
|||
expect(getApiKeyFromEnv("openai-native")).toBe("test-openai-key")
|
||||
})
|
||||
|
||||
it("should return API key from environment variable for litellm", () => {
|
||||
process.env.LITELLM_API_KEY = "test-litellm-key"
|
||||
expect(getApiKeyFromEnv("litellm")).toBe("test-litellm-key")
|
||||
})
|
||||
|
||||
it("should return undefined when API key is not set", () => {
|
||||
delete process.env.ANTHROPIC_API_KEY
|
||||
expect(getApiKeyFromEnv("anthropic")).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("getProviderSettings", () => {
|
||||
it("should return LiteLLM settings with API key, model, and base URL", () => {
|
||||
const settings = getProviderSettings("litellm", "test-api-key", "claude-3-sonnet", "http://localhost:4000")
|
||||
expect(settings).toEqual({
|
||||
apiProvider: "litellm",
|
||||
litellmApiKey: "test-api-key",
|
||||
litellmModelId: "claude-3-sonnet",
|
||||
litellmBaseUrl: "http://localhost:4000",
|
||||
})
|
||||
})
|
||||
|
||||
it("should return LiteLLM settings without base URL when not provided", () => {
|
||||
const settings = getProviderSettings("litellm", "test-api-key", "claude-3-sonnet")
|
||||
expect(settings).toEqual({
|
||||
apiProvider: "litellm",
|
||||
litellmApiKey: "test-api-key",
|
||||
litellmModelId: "claude-3-sonnet",
|
||||
})
|
||||
})
|
||||
|
||||
it("should return LiteLLM settings with only API key when model is not provided", () => {
|
||||
const settings = getProviderSettings("litellm", "test-api-key", undefined)
|
||||
expect(settings).toEqual({
|
||||
apiProvider: "litellm",
|
||||
litellmApiKey: "test-api-key",
|
||||
})
|
||||
})
|
||||
|
||||
it("should return anthropic settings correctly", () => {
|
||||
const settings = getProviderSettings("anthropic", "test-api-key", "claude-3-opus")
|
||||
expect(settings).toEqual({
|
||||
apiProvider: "anthropic",
|
||||
apiKey: "test-api-key",
|
||||
apiModelId: "claude-3-opus",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const envVarMap: Record<SupportedProvider, string> = {
|
|||
openrouter: "OPENROUTER_API_KEY",
|
||||
"vercel-ai-gateway": "VERCEL_AI_GATEWAY_API_KEY",
|
||||
roo: "ROO_API_KEY",
|
||||
litellm: "LITELLM_API_KEY",
|
||||
}
|
||||
|
||||
export function getEnvVarName(provider: SupportedProvider): string {
|
||||
|
|
@ -24,6 +25,7 @@ export function getProviderSettings(
|
|||
provider: SupportedProvider,
|
||||
apiKey: string | undefined,
|
||||
model: string | undefined,
|
||||
baseUrl?: string,
|
||||
): RooCodeSettings {
|
||||
const config: RooCodeSettings = { apiProvider: provider }
|
||||
|
||||
|
|
@ -52,6 +54,11 @@ export function getProviderSettings(
|
|||
if (apiKey) config.rooApiKey = apiKey
|
||||
if (model) config.apiModelId = model
|
||||
break
|
||||
case "litellm":
|
||||
if (apiKey) config.litellmApiKey = apiKey
|
||||
if (model) config.litellmModelId = model
|
||||
if (baseUrl) config.litellmBaseUrl = baseUrl
|
||||
break
|
||||
default:
|
||||
if (apiKey) config.apiKey = apiKey
|
||||
if (model) config.apiModelId = model
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export const supportedProviders = [
|
|||
"openrouter",
|
||||
"vercel-ai-gateway",
|
||||
"roo",
|
||||
"litellm",
|
||||
] as const satisfies ProviderName[]
|
||||
|
||||
export type SupportedProvider = (typeof supportedProviders)[number]
|
||||
|
|
@ -34,6 +35,7 @@ export type FlagOptions = {
|
|||
ephemeral: boolean
|
||||
oneshot: boolean
|
||||
outputFormat?: OutputFormat
|
||||
litellmBaseUrl?: string
|
||||
}
|
||||
|
||||
export enum OnboardingProviderChoice {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue