Coverage for .venv/lib/python3.13/site-packages/litellm/proxy/client/cli/main.py: 0%
91 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 12:01 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 12:01 +0000
1# stdlib imports
3# third party imports
4from typing import Final
6import click
8from litellm._version import version as litellm_version
9from litellm.proxy.client.health import HealthManagementClient
11from .commands.agents import agent_commands
12from .commands.auth import (
13 CliContextObj,
14 auth_group,
15 context_secret_vault,
16 get_stored_api_key,
17 login,
18 logout,
19 whoami,
20)
21from .commands.autoroute.commands import autoroute_group
22from .commands.chat import chat
23from .commands.config import config_commands, get_config_value, hidden_command_names
24from .commands.configure import configure_group, unconfigure_group
25from .commands.credentials import credentials
26from .commands.debug import debug
27from .commands.encryption import encryption
28from .commands.http import http
29from .commands.keys import keys
30from .commands.model_groups import model_groups
32# local imports
33from .commands.models import models
34from .commands.teams import teams
35from .commands.up import down, up
36from .commands.users import users
37from .interface import interactive_shell
40def print_version(base_url: str, api_key: str | None):
41 """Print CLI and server version info."""
42 click.echo(f"LiteLLM Proxy CLI Version: {litellm_version}")
43 if base_url:
44 click.echo(f"LiteLLM Proxy Server URL: {base_url}")
45 try:
46 health_client: Final = HealthManagementClient(base_url=base_url, api_key=api_key)
47 server_version: Final = health_client.get_server_version()
48 if server_version:
49 click.echo(f"LiteLLM Proxy Server Version: {server_version}")
50 else:
51 click.echo("LiteLLM Proxy Server Version: (unavailable)")
52 except Exception as e:
53 click.echo(f"Could not retrieve server version: {e}")
56class HideConfiguredCommandsGroup(click.Group):
57 """Group that omits operator-hidden commands from listings, still running them.
59 Deployments hand `lite` to users who should only see a curated subset of
60 commands (`lite config set hidden_commands codex,opencode`). Filtering the
61 listing rather than dropping the commands keeps anyone's existing scripts
62 working.
63 """
65 def list_commands(self, ctx: click.Context) -> list[str]:
66 hidden: Final = hidden_command_names()
67 return [name for name in super().list_commands(ctx) if name not in hidden]
70@click.group(cls=HideConfiguredCommandsGroup, invoke_without_command=True)
71@click.option(
72 "--version",
73 "-v",
74 "show_version",
75 is_flag=True,
76 help="Show the LiteLLM Proxy CLI and server version and exit.",
77)
78@click.option(
79 "--base-url",
80 envvar="LITELLM_PROXY_URL",
81 show_envvar=True,
82 default=None,
83 show_default="base_url from `lite config`, else http://localhost:4000",
84 help="Base URL of the LiteLLM proxy server",
85)
86@click.option(
87 "--api-key",
88 envvar="LITELLM_PROXY_API_KEY",
89 show_envvar=True,
90 help="API key for authentication",
91)
92@click.pass_context
93def cli(ctx: click.Context, show_version: bool, base_url: str | None, api_key: str | None) -> None:
94 """LiteLLM Proxy CLI - Manage your LiteLLM proxy server"""
95 ctx.ensure_object(dict)
97 stored_base_url: Final = get_config_value("base_url")
98 base_url_provided: Final = base_url is not None
100 # Normalize once here so every downstream command (login, agents, http, ...) can safely
101 # do f"{base_url}/some/path" without producing a double slash.
102 base_url = ((stored_base_url or "http://localhost:4000") if base_url is None else base_url).rstrip("/")
104 # If no API key provided via flag or environment variable, try to load from saved token.
105 # Pass base_url so we only use the stored key when it was issued for this server.
106 api_key_from_token_file: Final = api_key is None and ctx.invoked_subcommand not in ("configure", "unconfigure")
107 resolved_api_key: Final = (
108 get_stored_api_key(expected_base_url=base_url, vault=context_secret_vault(ctx))
109 if api_key_from_token_file
110 else api_key
111 )
113 ctx.obj["base_url"] = base_url
114 ctx.obj["api_key"] = resolved_api_key
115 ctx.obj["api_key_from_token_file"] = api_key_from_token_file
116 # `--base-url` defaults to localhost:4000 for local dev convenience, but
117 # apiKeyHelper is invoked bare (no flags) -- commands that must work
118 # unattended (print-token) need to tell "user didn't say" apart from
119 # "user said localhost:4000 on purpose" so they can fall back to
120 # whatever server the stored token was actually issued for. A base_url
121 # saved via `lite config set` counts as the user saying it.
122 ctx.obj["base_url_explicit"] = base_url_provided or bool(stored_base_url)
124 if show_version:
125 print_version(base_url, resolved_api_key)
126 ctx.exit()
128 # If no subcommand was invoked, start interactive mode
129 if ctx.invoked_subcommand is None:
130 interactive_shell(ctx)
133@cli.command()
134@click.pass_context
135def version(ctx: click.Context):
136 """Show the LiteLLM Proxy CLI and server version."""
137 ctx_obj: Final[CliContextObj] = ctx.obj
138 print_version(ctx_obj.get("base_url"), ctx_obj.get("api_key"))
141# Add authentication commands as top-level commands
142cli.add_command(login)
143cli.add_command(logout)
144cli.add_command(whoami)
145# Add the auth command group (e.g. `lite auth print-token`, used as Claude Code's apiKeyHelper)
146cli.add_command(auth_group, name="auth")
147# Add the models command group
148cli.add_command(models)
149# Add the credentials command group
150cli.add_command(credentials)
151# Add the encryption migration command group
152cli.add_command(encryption)
153# Add the chat command group
154cli.add_command(chat)
155# Add the http command group
156cli.add_command(http)
157cli.add_command(debug)
158# Add the keys command group
159cli.add_command(keys)
160# Add the teams command group
161cli.add_command(teams)
162# Add the users command group
163cli.add_command(users)
164# Add a top-level command per coding agent (claude, codex, opencode, ...)
165for agent_command in agent_commands():
166 cli.add_command(agent_command)
167# Add the up/down commands (route Claude Code through the local LiteLLM proxy)
168cli.add_command(up)
169cli.add_command(down)
170# Add the model-groups command group (discover models your key can access)
171cli.add_command(model_groups)
172# Add the autoroute command group (QA auto-routing against your real proxy)
173cli.add_command(autoroute_group, name="autoroute")
174cli.add_command(config_commands)
175# Add configure/unconfigure (persistently wire a coding agent to the proxy with a virtual key)
176cli.add_command(configure_group)
177cli.add_command(unconfigure_group)
180LITELLM_PROXY_DEPRECATION_NOTICE: Final = (
181 "The `litellm-proxy` command is deprecated and will be removed in a future release; "
182 "run `lite` instead, it takes the same commands and options."
183)
186def litellm_proxy_cli() -> None:
187 click.secho(LITELLM_PROXY_DEPRECATION_NOTICE, err=True, fg="yellow")
188 cli()
191if __name__ == "__main__":
192 cli()