11import contextlib
2+ import functools
23import io
34import logging
45import os
1011from typing import Optional , Tuple
1112
1213import click
13- import llm
14- from llm .cli import cli
14+
15+ try :
16+ import llm
17+
18+ LLM_IMPORTED = True
19+ except ImportError :
20+ LLM_IMPORTED = False
21+ try :
22+ from llm .cli import cli
23+
24+ LLM_CLI_IMPORTED = True
25+ except ImportError :
26+ LLM_CLI_IMPORTED = False
1527
1628from mycli .packages .special .main import Verbosity , parse_special_command
1729
1830log = logging .getLogger (__name__ )
1931
20- LLM_CLI_COMMANDS = list (cli .commands .keys ())
21- MODELS = {x .model_id : None for x in llm .get_models ()}
2232LLM_TEMPLATE_NAME = "mycli-llm-template"
2333
2434
@@ -67,7 +77,7 @@ def build_command_tree(cmd):
6777 if isinstance (cmd , click .Group ):
6878 for name , subcmd in cmd .commands .items ():
6979 if cmd .name == "models" and name == "default" :
70- tree [name ] = MODELS
80+ tree [name ] = { x . model_id : None for x in llm . get_models ()}
7181 else :
7282 tree [name ] = build_command_tree (subcmd )
7383 else :
@@ -76,7 +86,7 @@ def build_command_tree(cmd):
7686
7787
7888# Generate the command tree for autocompletion
79- COMMAND_TREE = build_command_tree (cli ) if cli else {}
89+ COMMAND_TREE = build_command_tree (cli ) if LLM_CLI_IMPORTED is True else {}
8090
8191
8292def get_completions (tokens , tree = COMMAND_TREE ):
@@ -120,7 +130,25 @@ def __init__(self, results=None):
120130# Plugins directory
121131# https://llm.datasette.io/en/stable/plugins/directory.html
122132"""
133+
134+ NEED_DEPENDENCIES = """
135+ To enable LLM features you need to install mycli with LLM support:
136+
137+ pip install 'mycli[llm]'
138+
139+ or
140+
141+ pip install 'mycli[all]'
142+
143+ or install LLM libraries separately
144+
145+ pip install llm
146+
147+ This is required to use the \\ llm command.
148+ """
149+
123150_SQL_CODE_FENCE = r"```sql\n(.*?)\n```"
151+
124152PROMPT = """
125153You are a helpful assistant who is a MySQL expert. You are embedded in a mysql
126154cli tool called mycli.
@@ -159,8 +187,16 @@ def ensure_mycli_template(replace=False):
159187 return
160188
161189
190+ @functools .cache
191+ def cli_commands () -> list [str ]:
192+ return list (cli .commands .keys ())
193+
194+
162195def handle_llm (text , cur ) -> Tuple [str , Optional [str ], float ]:
163196 _ , verbosity , arg = parse_special_command (text )
197+ if not LLM_IMPORTED :
198+ output = [(None , None , None , NEED_DEPENDENCIES )]
199+ raise FinishIteration (output )
164200 if not arg .strip ():
165201 output = [(None , None , None , USAGE )]
166202 raise FinishIteration (output )
@@ -176,7 +212,7 @@ def handle_llm(text, cur) -> Tuple[str, Optional[str], float]:
176212 capture_output = False
177213 use_context = False
178214 restart = True
179- elif parts and parts [0 ] in LLM_CLI_COMMANDS :
215+ elif parts and parts [0 ] in cli_commands () :
180216 capture_output = False
181217 use_context = False
182218 elif parts and parts [0 ] == "--help" :
0 commit comments