Coverage for .venv/lib/python3.13/site-packages/litellm/proxy/client/cli/interface.py: 0%

114 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 12:01 +0000

1# stdlib imports 

2import os 

3import sys 

4from typing import Final 

5 

6# third party imports 

7import click 

8 

9from litellm._logging import verbose_logger 

10 

11 

12def styled_prompt(): 

13 """Create a styled blue box prompt for user input.""" 

14 

15 # Get terminal height to ensure we have enough space 

16 try: 

17 terminal_height: Final = os.get_terminal_size().lines 

18 # Ensure we have at least 5 lines of space (for the box + some buffer) 

19 if terminal_height < 10: 

20 # If terminal is too small, just add some newlines to push content up 

21 click.echo("\n" * 3) 

22 except Exception as e: 

23 # Fallback if we can't get terminal size 

24 verbose_logger.debug("Error getting terminal size: %s", e) 

25 click.echo("\n" * 3) 

26 

27 # ASCII box drawing characters 

28 top_left: Final = "+" 

29 top_right: Final = "+" 

30 bottom_left: Final = "+" 

31 bottom_right: Final = "+" 

32 horizontal: Final = "-" 

33 vertical: Final = "|" 

34 

35 # Create the box with increased width 

36 width: Final = 80 

37 top_line: Final = top_left + horizontal * (width - 2) + top_right 

38 bottom_line: Final = bottom_left + horizontal * (width - 2) + bottom_right 

39 

40 # Create styled elements 

41 left_border: Final = click.style(vertical, fg="blue", bold=True) 

42 right_border: Final = click.style(vertical, fg="blue", bold=True) 

43 prompt_text: Final = click.style("> ", fg="cyan", bold=True) 

44 

45 # Display the complete box structure first to reserve space 

46 click.echo(click.style(top_line, fg="blue", bold=True)) 

47 

48 # Create empty space in the box for input 

49 empty_space: Final = " " * (width - 4) 

50 click.echo(f"{left_border} {empty_space} {right_border}") 

51 

52 # Display bottom border to complete the box 

53 click.echo(click.style(bottom_line, fg="blue", bold=True)) 

54 

55 # Now move cursor up to the input line and get input 

56 click.echo("\033[2A", nl=False) # Move cursor up 2 lines 

57 click.echo(f"\r{left_border} {prompt_text}", nl=False) # Position at start of input line 

58 

59 try: 

60 # Get user input 

61 user_input: Final = input().strip() 

62 

63 # Move cursor down to after the box 

64 click.echo("\033[1B") # Move cursor down 1 line 

65 click.echo("") # Add some space after 

66 

67 except (KeyboardInterrupt, EOFError): 

68 # Move cursor down and add space 

69 click.echo("\033[1B") 

70 click.echo("") 

71 raise 

72 

73 return user_input 

74 

75 

76def show_commands(): 

77 """Display available commands, minus any the operator chose to hide.""" 

78 from .commands.agents import agent_commands 

79 from .commands.config import hidden_command_names 

80 

81 commands = [ 

82 ("login", "Authenticate with the LiteLLM proxy server"), 

83 ("logout", "Clear stored authentication"), 

84 ("whoami", "Show current authentication status"), 

85 ("models", "Manage and view model configurations"), 

86 ("credentials", "Manage API credentials"), 

87 ("chat", "Interactive streaming chat with models"), 

88 ("http", "Make HTTP requests to the proxy"), 

89 ("keys", "Manage API keys"), 

90 ("teams", "Manage teams and team assignments"), 

91 ("users", "Manage users"), 

92 ] 

93 commands += [(c.name, c.get_short_help_str()) for c in agent_commands()] 

94 commands += [ 

95 ("version", "Show version information"), 

96 ("help", "Show this help message"), 

97 ("quit", "Exit the interactive session"), 

98 ] 

99 

100 hidden: Final = hidden_command_names() 

101 

102 click.echo("Available commands:") 

103 for cmd, description in commands: 

104 if cmd not in hidden: 

105 click.echo(f" {cmd:<20} {description}") 

106 click.echo() 

107 

108 

109def setup_shell(ctx: click.Context): 

110 """Set up the interactive shell with banner and initial info.""" 

111 from litellm.proxy.common_utils.banner import show_banner 

112 

113 show_banner() 

114 

115 # Show server connection info 

116 base_url: Final = ctx.obj.get("base_url") 

117 click.secho(f"Connected to LiteLLM server: {base_url}\n", fg="green") 

118 

119 show_commands() 

120 

121 

122def handle_special_commands(user_input: str) -> bool: 

123 """Handle special commands like exit, help, clear. Returns True if command was handled.""" 

124 if user_input.lower() in ["exit", "quit"]: 

125 click.echo("Goodbye!") 

126 return True 

127 elif user_input.lower() == "help": 

128 click.echo("") # Add space before help 

129 show_commands() 

130 return True 

131 elif user_input.lower() == "clear": 

132 click.clear() 

133 from litellm.proxy.common_utils.banner import show_banner 

134 

135 show_banner() 

136 show_commands() 

137 return True 

138 

139 return False 

140 

141 

142def execute_command(user_input: str, ctx: click.Context): 

143 """Parse and execute a command.""" 

144 # Parse command and arguments 

145 parts: Final = user_input.split() 

146 command: Final = parts[0] 

147 args: Final = parts[1:] if len(parts) > 1 else [] 

148 

149 # Import cli here to avoid circular import 

150 from . import main 

151 

152 cli: Final = main.cli 

153 

154 # Check if command exists 

155 if command not in cli.commands: 

156 click.echo(f"Unknown command: {command}") 

157 click.echo("Type 'help' to see available commands.") 

158 return 

159 

160 # Execute the command 

161 try: 

162 # Create a new argument list for click to parse 

163 sys.argv = ["lite"] + [command] + args 

164 

165 # Get the command object and invoke it 

166 cmd: Final = cli.commands[command] 

167 

168 # Create a new context for the subcommand 

169 with ctx.scope(): 

170 cmd.main(args, parent=ctx, standalone_mode=False) 

171 

172 except click.ClickException as e: 

173 e.show() 

174 except click.Abort: 

175 click.echo("Command aborted.") 

176 except SystemExit: 

177 # Prevent the interactive shell from exiting on command errors 

178 pass 

179 except Exception as e: 

180 click.echo(f"Error executing command: {e}") 

181 

182 

183def interactive_shell(ctx: click.Context): 

184 """Run the interactive shell.""" 

185 setup_shell(ctx) 

186 

187 while True: 

188 try: 

189 # Add some space before the input box to ensure it's positioned well 

190 click.echo("\n") # Extra spacing 

191 

192 # Show styled prompt 

193 user_input = styled_prompt() 

194 

195 if not user_input: 

196 continue 

197 

198 # Handle special commands 

199 if handle_special_commands(user_input): 

200 if user_input.lower() in ["exit", "quit"]: 

201 break 

202 continue 

203 

204 # Execute regular commands 

205 execute_command(user_input, ctx) 

206 

207 except (KeyboardInterrupt, EOFError): 

208 click.echo("\nGoodbye!") 

209 break 

210 except Exception as e: 

211 click.echo(f"Error: {e}")