code-puppy 0.0.53__py3-none-any.whl → 0.0.54__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- code_puppy/__init__.py +1 -0
- code_puppy/agent.py +20 -8
- code_puppy/agent_prompts.py +2 -3
- code_puppy/command_line/file_path_completion.py +11 -4
- code_puppy/command_line/meta_command_handler.py +48 -28
- code_puppy/command_line/model_picker_completion.py +27 -13
- code_puppy/command_line/prompt_toolkit_completion.py +95 -51
- code_puppy/command_line/utils.py +8 -6
- code_puppy/config.py +22 -11
- code_puppy/main.py +32 -22
- code_puppy/model_factory.py +7 -7
- code_puppy/session_memory.py +31 -19
- code_puppy/tools/__init__.py +1 -0
- code_puppy/tools/code_map.py +16 -11
- code_puppy/tools/command_runner.py +160 -63
- code_puppy/tools/common.py +1 -1
- code_puppy/tools/file_modifications.py +352 -302
- code_puppy/tools/file_operations.py +109 -183
- code_puppy/tools/web_search.py +24 -8
- code_puppy/version_checker.py +4 -4
- {code_puppy-0.0.53.dist-info → code_puppy-0.0.54.dist-info}/METADATA +1 -1
- code_puppy-0.0.54.dist-info/RECORD +28 -0
- code_puppy-0.0.53.dist-info/RECORD +0 -28
- {code_puppy-0.0.53.data → code_puppy-0.0.54.data}/data/code_puppy/models.json +0 -0
- {code_puppy-0.0.53.dist-info → code_puppy-0.0.54.dist-info}/WHEEL +0 -0
- {code_puppy-0.0.53.dist-info → code_puppy-0.0.54.dist-info}/entry_points.txt +0 -0
- {code_puppy-0.0.53.dist-info → code_puppy-0.0.54.dist-info}/licenses/LICENSE +0 -0
code_puppy/__init__.py
CHANGED
code_puppy/agent.py
CHANGED
|
@@ -18,14 +18,16 @@ from code_puppy.session_memory import SessionMemory
|
|
|
18
18
|
MODELS_JSON_PATH = os.environ.get("MODELS_JSON_PATH", None)
|
|
19
19
|
|
|
20
20
|
# Load puppy rules if provided
|
|
21
|
-
PUPPY_RULES_PATH = Path(
|
|
21
|
+
PUPPY_RULES_PATH = Path(".puppy_rules")
|
|
22
22
|
PUPPY_RULES = None
|
|
23
23
|
if PUPPY_RULES_PATH.exists():
|
|
24
|
-
with open(PUPPY_RULES_PATH,
|
|
24
|
+
with open(PUPPY_RULES_PATH, "r") as f:
|
|
25
25
|
PUPPY_RULES = f.read()
|
|
26
26
|
|
|
27
|
+
|
|
27
28
|
class AgentResponse(pydantic.BaseModel):
|
|
28
29
|
"""Represents a response from the agent."""
|
|
30
|
+
|
|
29
31
|
output_message: str = pydantic.Field(
|
|
30
32
|
..., description="The final output message to display to the user"
|
|
31
33
|
)
|
|
@@ -33,31 +35,39 @@ class AgentResponse(pydantic.BaseModel):
|
|
|
33
35
|
False, description="True if user input is needed to continue the task"
|
|
34
36
|
)
|
|
35
37
|
|
|
38
|
+
|
|
36
39
|
# --- NEW DYNAMIC AGENT LOGIC ---
|
|
37
40
|
_LAST_MODEL_NAME = None
|
|
38
41
|
_code_generation_agent = None
|
|
39
42
|
_session_memory = None
|
|
40
43
|
|
|
44
|
+
|
|
41
45
|
def session_memory():
|
|
42
|
-
|
|
46
|
+
"""
|
|
43
47
|
Returns a singleton SessionMemory instance to allow agent and tools to persist and recall context/history.
|
|
44
|
-
|
|
48
|
+
"""
|
|
45
49
|
global _session_memory
|
|
46
50
|
if _session_memory is None:
|
|
47
51
|
_session_memory = SessionMemory()
|
|
48
52
|
return _session_memory
|
|
49
53
|
|
|
54
|
+
|
|
50
55
|
def reload_code_generation_agent():
|
|
51
56
|
"""Force-reload the agent, usually after a model change."""
|
|
52
57
|
global _code_generation_agent, _LAST_MODEL_NAME
|
|
53
58
|
from code_puppy.config import get_model_name
|
|
59
|
+
|
|
54
60
|
model_name = get_model_name()
|
|
55
|
-
console.print(f
|
|
56
|
-
models_path =
|
|
61
|
+
console.print(f"[bold cyan]Loading Model: {model_name}[/bold cyan]")
|
|
62
|
+
models_path = (
|
|
63
|
+
Path(MODELS_JSON_PATH)
|
|
64
|
+
if MODELS_JSON_PATH
|
|
65
|
+
else Path(__file__).parent / "models.json"
|
|
66
|
+
)
|
|
57
67
|
model = ModelFactory.get_model(model_name, ModelFactory.load_config(models_path))
|
|
58
68
|
instructions = get_system_prompt()
|
|
59
69
|
if PUPPY_RULES:
|
|
60
|
-
instructions += f
|
|
70
|
+
instructions += f"\n{PUPPY_RULES}"
|
|
61
71
|
agent = Agent(
|
|
62
72
|
model=model,
|
|
63
73
|
instructions=instructions,
|
|
@@ -69,11 +79,12 @@ def reload_code_generation_agent():
|
|
|
69
79
|
_LAST_MODEL_NAME = model_name
|
|
70
80
|
# NEW: Log session event
|
|
71
81
|
try:
|
|
72
|
-
session_memory().log_task(f
|
|
82
|
+
session_memory().log_task(f"Agent loaded with model: {model_name}")
|
|
73
83
|
except Exception:
|
|
74
84
|
pass
|
|
75
85
|
return _code_generation_agent
|
|
76
86
|
|
|
87
|
+
|
|
77
88
|
def get_code_generation_agent(force_reload=False):
|
|
78
89
|
"""
|
|
79
90
|
Retrieve the agent with the currently set MODEL_NAME.
|
|
@@ -81,6 +92,7 @@ def get_code_generation_agent(force_reload=False):
|
|
|
81
92
|
"""
|
|
82
93
|
global _code_generation_agent, _LAST_MODEL_NAME
|
|
83
94
|
from code_puppy.config import get_model_name
|
|
95
|
+
|
|
84
96
|
model_name = get_model_name()
|
|
85
97
|
if _code_generation_agent is None or _LAST_MODEL_NAME != model_name or force_reload:
|
|
86
98
|
return reload_code_generation_agent()
|
code_puppy/agent_prompts.py
CHANGED
|
@@ -106,10 +106,9 @@ Return your final response as a structured output having the following fields:
|
|
|
106
106
|
* awaiting_user_input: True if user input is needed to continue the task. If you get an error, you might consider asking the user for help.
|
|
107
107
|
"""
|
|
108
108
|
|
|
109
|
+
|
|
109
110
|
def get_system_prompt():
|
|
110
111
|
"""Returns the main system prompt, populated with current puppy and owner name."""
|
|
111
112
|
return SYSTEM_PROMPT_TEMPLATE.format(
|
|
112
|
-
puppy_name=get_puppy_name(),
|
|
113
|
-
owner_name=get_owner_name()
|
|
113
|
+
puppy_name=get_puppy_name(), owner_name=get_owner_name()
|
|
114
114
|
)
|
|
115
|
-
|
|
@@ -4,18 +4,23 @@ from typing import Iterable
|
|
|
4
4
|
from prompt_toolkit.completion import Completer, Completion
|
|
5
5
|
from prompt_toolkit.document import Document
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
class FilePathCompleter(Completer):
|
|
8
9
|
"""A simple file path completer that works with a trigger symbol."""
|
|
10
|
+
|
|
9
11
|
def __init__(self, symbol: str = "@"):
|
|
10
12
|
self.symbol = symbol
|
|
11
|
-
|
|
13
|
+
|
|
14
|
+
def get_completions(
|
|
15
|
+
self, document: Document, complete_event
|
|
16
|
+
) -> Iterable[Completion]:
|
|
12
17
|
text = document.text
|
|
13
18
|
cursor_position = document.cursor_position
|
|
14
19
|
text_before_cursor = text[:cursor_position]
|
|
15
20
|
if self.symbol not in text_before_cursor:
|
|
16
21
|
return
|
|
17
22
|
symbol_pos = text_before_cursor.rfind(self.symbol)
|
|
18
|
-
text_after_symbol = text_before_cursor[symbol_pos + len(self.symbol):]
|
|
23
|
+
text_after_symbol = text_before_cursor[symbol_pos + len(self.symbol) :]
|
|
19
24
|
start_position = -(len(text_after_symbol))
|
|
20
25
|
try:
|
|
21
26
|
pattern = text_after_symbol + "*"
|
|
@@ -36,7 +41,9 @@ class FilePathCompleter(Completer):
|
|
|
36
41
|
else:
|
|
37
42
|
paths = glob.glob(pattern)
|
|
38
43
|
if not pattern.startswith(".") and not pattern.startswith("*/."):
|
|
39
|
-
paths = [
|
|
44
|
+
paths = [
|
|
45
|
+
p for p in paths if not os.path.basename(p).startswith(".")
|
|
46
|
+
]
|
|
40
47
|
paths.sort()
|
|
41
48
|
for path in paths:
|
|
42
49
|
is_dir = os.path.isdir(path)
|
|
@@ -49,7 +56,7 @@ class FilePathCompleter(Completer):
|
|
|
49
56
|
elif text_after_symbol.startswith("~"):
|
|
50
57
|
home = os.path.expanduser("~")
|
|
51
58
|
if path.startswith(home):
|
|
52
|
-
display_path = "~" + path[len(home):]
|
|
59
|
+
display_path = "~" + path[len(home) :]
|
|
53
60
|
else:
|
|
54
61
|
display_path = path
|
|
55
62
|
else:
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import os
|
|
2
|
+
from rich.console import Console
|
|
3
|
+
from code_puppy.command_line.model_picker_completion import (
|
|
4
|
+
load_model_names,
|
|
5
|
+
update_model_in_input,
|
|
6
|
+
)
|
|
7
|
+
from code_puppy.command_line.utils import make_directory_table
|
|
8
|
+
|
|
9
|
+
META_COMMANDS_HELP = """
|
|
2
10
|
[bold magenta]Meta Commands Help[/bold magenta]
|
|
3
11
|
~help, ~h Show this help message
|
|
4
12
|
~cd [dir] Change directory or show directories
|
|
@@ -6,17 +14,14 @@ META_COMMANDS_HELP = '''
|
|
|
6
14
|
~m <model> Set active model
|
|
7
15
|
~show Show puppy status info
|
|
8
16
|
~<unknown> Show unknown meta command warning
|
|
9
|
-
|
|
17
|
+
"""
|
|
10
18
|
|
|
11
|
-
from code_puppy.command_line.model_picker_completion import update_model_in_input, load_model_names, get_active_model
|
|
12
|
-
from rich.console import Console
|
|
13
|
-
import os
|
|
14
|
-
from code_puppy.command_line.utils import make_directory_table
|
|
15
19
|
|
|
16
20
|
def handle_meta_command(command: str, console: Console) -> bool:
|
|
17
21
|
# ~codemap (code structure visualization)
|
|
18
22
|
if command.startswith("~codemap"):
|
|
19
23
|
from code_puppy.tools.code_map import make_code_map
|
|
24
|
+
|
|
20
25
|
tokens = command.split()
|
|
21
26
|
if len(tokens) > 1:
|
|
22
27
|
target_dir = os.path.expanduser(tokens[1])
|
|
@@ -26,7 +31,7 @@ def handle_meta_command(command: str, console: Console) -> bool:
|
|
|
26
31
|
tree = make_code_map(target_dir, show_doc=True)
|
|
27
32
|
console.print(tree)
|
|
28
33
|
except Exception as e:
|
|
29
|
-
console.print(f
|
|
34
|
+
console.print(f"[red]Error generating code map:[/red] {e}")
|
|
30
35
|
return True
|
|
31
36
|
"""
|
|
32
37
|
Handle meta/config commands prefixed with '~'.
|
|
@@ -40,7 +45,7 @@ def handle_meta_command(command: str, console: Console) -> bool:
|
|
|
40
45
|
table = make_directory_table()
|
|
41
46
|
console.print(table)
|
|
42
47
|
except Exception as e:
|
|
43
|
-
console.print(f
|
|
48
|
+
console.print(f"[red]Error listing directory:[/red] {e}")
|
|
44
49
|
return True
|
|
45
50
|
elif len(tokens) == 2:
|
|
46
51
|
dirname = tokens[1]
|
|
@@ -49,36 +54,41 @@ def handle_meta_command(command: str, console: Console) -> bool:
|
|
|
49
54
|
target = os.path.join(os.getcwd(), target)
|
|
50
55
|
if os.path.isdir(target):
|
|
51
56
|
os.chdir(target)
|
|
52
|
-
console.print(
|
|
57
|
+
console.print(
|
|
58
|
+
f"[bold green]Changed directory to:[/bold green] [cyan]{target}[/cyan]"
|
|
59
|
+
)
|
|
53
60
|
else:
|
|
54
|
-
console.print(f
|
|
61
|
+
console.print(f"[red]Not a directory:[/red] [bold]{dirname}[/bold]")
|
|
55
62
|
return True
|
|
56
63
|
|
|
57
64
|
if command.strip().startswith("~show"):
|
|
58
|
-
from code_puppy.config import get_puppy_name, get_owner_name
|
|
59
65
|
from code_puppy.command_line.model_picker_completion import get_active_model
|
|
66
|
+
from code_puppy.config import get_owner_name, get_puppy_name
|
|
67
|
+
|
|
60
68
|
puppy_name = get_puppy_name()
|
|
61
69
|
owner_name = get_owner_name()
|
|
62
70
|
model = get_active_model()
|
|
63
71
|
from code_puppy.config import get_yolo_mode
|
|
72
|
+
|
|
64
73
|
yolo_mode = get_yolo_mode()
|
|
65
|
-
console.print(f
|
|
74
|
+
console.print(f"""[bold magenta]🐶 Puppy Status[/bold magenta]
|
|
66
75
|
\n[bold]puppy_name:[/bold] [cyan]{puppy_name}[/cyan]
|
|
67
76
|
[bold]owner_name:[/bold] [cyan]{owner_name}[/cyan]
|
|
68
77
|
[bold]model:[/bold] [green]{model}[/green]
|
|
69
|
-
[bold]YOLO_MODE:[/bold] {
|
|
70
|
-
|
|
78
|
+
[bold]YOLO_MODE:[/bold] {"[red]ON[/red]" if yolo_mode else "[yellow]off[/yellow]"}
|
|
79
|
+
""")
|
|
71
80
|
return True
|
|
72
81
|
|
|
73
82
|
if command.startswith("~set"):
|
|
74
83
|
# Syntax: ~set KEY=VALUE or ~set KEY VALUE
|
|
75
|
-
from code_puppy.config import
|
|
84
|
+
from code_puppy.config import get_config_keys, set_config_value
|
|
85
|
+
|
|
76
86
|
tokens = command.split(None, 2)
|
|
77
|
-
argstr = command[len(
|
|
87
|
+
argstr = command[len("~set") :].strip()
|
|
78
88
|
key = None
|
|
79
89
|
value = None
|
|
80
|
-
if
|
|
81
|
-
key, value = argstr.split(
|
|
90
|
+
if "=" in argstr:
|
|
91
|
+
key, value = argstr.split("=", 1)
|
|
82
92
|
key = key.strip()
|
|
83
93
|
value = value.strip()
|
|
84
94
|
elif len(tokens) >= 3:
|
|
@@ -86,16 +96,18 @@ def handle_meta_command(command: str, console: Console) -> bool:
|
|
|
86
96
|
value = tokens[2]
|
|
87
97
|
elif len(tokens) == 2:
|
|
88
98
|
key = tokens[1]
|
|
89
|
-
value =
|
|
99
|
+
value = ""
|
|
90
100
|
else:
|
|
91
|
-
console.print(
|
|
92
|
-
console.print(
|
|
101
|
+
console.print("[yellow]Usage:[/yellow] ~set KEY=VALUE or ~set KEY VALUE")
|
|
102
|
+
console.print("Config keys: " + ", ".join(get_config_keys()))
|
|
93
103
|
return True
|
|
94
104
|
if key:
|
|
95
105
|
set_config_value(key, value)
|
|
96
|
-
console.print(
|
|
106
|
+
console.print(
|
|
107
|
+
f'[green]🌶 Set[/green] [cyan]{key}[/cyan] = "{value}" in puppy.cfg!'
|
|
108
|
+
)
|
|
97
109
|
else:
|
|
98
|
-
console.print(
|
|
110
|
+
console.print("[red]You must supply a key.[/red]")
|
|
99
111
|
return True
|
|
100
112
|
|
|
101
113
|
if command.startswith("~m"):
|
|
@@ -103,26 +115,34 @@ def handle_meta_command(command: str, console: Console) -> bool:
|
|
|
103
115
|
new_input = update_model_in_input(command)
|
|
104
116
|
if new_input is not None:
|
|
105
117
|
from code_puppy.agent import get_code_generation_agent
|
|
118
|
+
|
|
106
119
|
model = get_active_model()
|
|
107
120
|
get_code_generation_agent(force_reload=True)
|
|
108
|
-
console.print(
|
|
121
|
+
console.print(
|
|
122
|
+
f"[bold green]Active model set and loaded:[/bold green] [cyan]{model}[/cyan]"
|
|
123
|
+
)
|
|
109
124
|
return True
|
|
110
125
|
# If no model matched, show available models
|
|
111
126
|
model_names = load_model_names()
|
|
112
127
|
console.print(f"[yellow]Available models:[/yellow] {', '.join(model_names)}")
|
|
113
|
-
console.print(
|
|
128
|
+
console.print("[yellow]Usage:[/yellow] ~m <model_name>")
|
|
114
129
|
return True
|
|
115
130
|
if command in ("~help", "~h"):
|
|
116
131
|
console.print(META_COMMANDS_HELP)
|
|
117
132
|
return True
|
|
118
133
|
if command.startswith("~"):
|
|
119
|
-
name = command[1:].split()[0] if len(command)>1 else ""
|
|
134
|
+
name = command[1:].split()[0] if len(command) > 1 else ""
|
|
120
135
|
if name:
|
|
121
|
-
console.print(
|
|
136
|
+
console.print(
|
|
137
|
+
f"[yellow]Unknown meta command:[/yellow] {command}\n[dim]Type ~help for options.[/dim]"
|
|
138
|
+
)
|
|
122
139
|
else:
|
|
123
140
|
# Show current model ONLY here
|
|
124
141
|
from code_puppy.command_line.model_picker_completion import get_active_model
|
|
142
|
+
|
|
125
143
|
current_model = get_active_model()
|
|
126
|
-
console.print(
|
|
144
|
+
console.print(
|
|
145
|
+
f"[bold green]Current Model:[/bold green] [cyan]{current_model}[/cyan]"
|
|
146
|
+
)
|
|
127
147
|
return True
|
|
128
148
|
return False
|
|
@@ -9,14 +9,16 @@ from code_puppy.config import get_model_name, set_model_name
|
|
|
9
9
|
|
|
10
10
|
MODELS_JSON_PATH = os.environ.get("MODELS_JSON_PATH")
|
|
11
11
|
if not MODELS_JSON_PATH:
|
|
12
|
-
MODELS_JSON_PATH = os.path.join(os.path.dirname(__file__),
|
|
12
|
+
MODELS_JSON_PATH = os.path.join(os.path.dirname(__file__), "..", "models.json")
|
|
13
13
|
MODELS_JSON_PATH = os.path.abspath(MODELS_JSON_PATH)
|
|
14
14
|
|
|
15
|
+
|
|
15
16
|
def load_model_names():
|
|
16
|
-
with open(MODELS_JSON_PATH,
|
|
17
|
+
with open(MODELS_JSON_PATH, "r") as f:
|
|
17
18
|
models = json.load(f)
|
|
18
19
|
return list(models.keys())
|
|
19
20
|
|
|
21
|
+
|
|
20
22
|
def get_active_model():
|
|
21
23
|
"""
|
|
22
24
|
Returns the active model from the config using get_model_name().
|
|
@@ -24,37 +26,43 @@ def get_active_model():
|
|
|
24
26
|
"""
|
|
25
27
|
return get_model_name()
|
|
26
28
|
|
|
29
|
+
|
|
27
30
|
def set_active_model(model_name: str):
|
|
28
31
|
"""
|
|
29
32
|
Sets the active model name by updating both config (for persistence)
|
|
30
33
|
and env (for process lifetime override).
|
|
31
34
|
"""
|
|
32
35
|
set_model_name(model_name)
|
|
33
|
-
os.environ[
|
|
36
|
+
os.environ["MODEL_NAME"] = model_name.strip()
|
|
34
37
|
# Reload agent globally
|
|
35
38
|
try:
|
|
36
|
-
from code_puppy.agent import reload_code_generation_agent
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
from code_puppy.agent import reload_code_generation_agent
|
|
40
|
+
|
|
41
|
+
reload_code_generation_agent() # This will reload dynamically everywhere
|
|
42
|
+
except Exception:
|
|
39
43
|
pass # If reload fails, agent will still be switched next interpreter run
|
|
40
44
|
|
|
45
|
+
|
|
41
46
|
class ModelNameCompleter(Completer):
|
|
42
47
|
"""
|
|
43
48
|
A completer that triggers on '~m' to show available models from models.json.
|
|
44
49
|
Only '~m' (not just '~') will trigger the dropdown.
|
|
45
50
|
"""
|
|
51
|
+
|
|
46
52
|
def __init__(self, trigger: str = "~m"):
|
|
47
53
|
self.trigger = trigger
|
|
48
54
|
self.model_names = load_model_names()
|
|
49
55
|
|
|
50
|
-
def get_completions(
|
|
56
|
+
def get_completions(
|
|
57
|
+
self, document: Document, complete_event
|
|
58
|
+
) -> Iterable[Completion]:
|
|
51
59
|
text = document.text
|
|
52
60
|
cursor_position = document.cursor_position
|
|
53
61
|
text_before_cursor = text[:cursor_position]
|
|
54
62
|
if self.trigger not in text_before_cursor:
|
|
55
63
|
return
|
|
56
64
|
symbol_pos = text_before_cursor.rfind(self.trigger)
|
|
57
|
-
text_after_trigger = text_before_cursor[symbol_pos + len(self.trigger):]
|
|
65
|
+
text_after_trigger = text_before_cursor[symbol_pos + len(self.trigger) :]
|
|
58
66
|
start_position = -(len(text_after_trigger))
|
|
59
67
|
for model_name in self.model_names:
|
|
60
68
|
meta = "Model (selected)" if model_name == get_active_model() else "Model"
|
|
@@ -65,25 +73,31 @@ class ModelNameCompleter(Completer):
|
|
|
65
73
|
display_meta=meta,
|
|
66
74
|
)
|
|
67
75
|
|
|
76
|
+
|
|
68
77
|
def update_model_in_input(text: str) -> Optional[str]:
|
|
69
78
|
# If input starts with ~m and a model name, set model and strip it out
|
|
70
79
|
content = text.strip()
|
|
71
80
|
if content.startswith("~m"):
|
|
72
81
|
rest = content[2:].strip()
|
|
73
82
|
for model in load_model_names():
|
|
74
|
-
if rest
|
|
83
|
+
if rest == model:
|
|
75
84
|
set_active_model(model)
|
|
76
85
|
# Remove ~mmodel from the input
|
|
77
|
-
idx = text.find("~m"+model)
|
|
86
|
+
idx = text.find("~m" + model)
|
|
78
87
|
if idx != -1:
|
|
79
|
-
new_text = (text[:idx] + text[idx+len("~m"+model):]).strip()
|
|
88
|
+
new_text = (text[:idx] + text[idx + len("~m" + model) :]).strip()
|
|
80
89
|
return new_text
|
|
81
90
|
return None
|
|
82
91
|
|
|
83
|
-
|
|
92
|
+
|
|
93
|
+
async def get_input_with_model_completion(
|
|
94
|
+
prompt_str: str = ">>> ", trigger: str = "~m", history_file: Optional[str] = None
|
|
95
|
+
) -> str:
|
|
84
96
|
history = FileHistory(os.path.expanduser(history_file)) if history_file else None
|
|
85
97
|
session = PromptSession(
|
|
86
|
-
completer=ModelNameCompleter(trigger),
|
|
98
|
+
completer=ModelNameCompleter(trigger),
|
|
99
|
+
history=history,
|
|
100
|
+
complete_while_typing=True,
|
|
87
101
|
)
|
|
88
102
|
text = await session.prompt_async(prompt_str)
|
|
89
103
|
possibly_stripped = update_model_in_input(text)
|