letta-nightly 0.1.7.dev20240924104148__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.
Potentially problematic release.
This version of letta-nightly might be problematic. Click here for more details.
- letta/__init__.py +24 -0
- letta/__main__.py +3 -0
- letta/agent.py +1427 -0
- letta/agent_store/chroma.py +295 -0
- letta/agent_store/db.py +546 -0
- letta/agent_store/lancedb.py +177 -0
- letta/agent_store/milvus.py +198 -0
- letta/agent_store/qdrant.py +201 -0
- letta/agent_store/storage.py +188 -0
- letta/benchmark/benchmark.py +96 -0
- letta/benchmark/constants.py +14 -0
- letta/cli/cli.py +689 -0
- letta/cli/cli_config.py +1282 -0
- letta/cli/cli_load.py +166 -0
- letta/client/__init__.py +0 -0
- letta/client/admin.py +171 -0
- letta/client/client.py +2360 -0
- letta/client/streaming.py +90 -0
- letta/client/utils.py +61 -0
- letta/config.py +484 -0
- letta/configs/anthropic.json +13 -0
- letta/configs/letta_hosted.json +11 -0
- letta/configs/openai.json +12 -0
- letta/constants.py +134 -0
- letta/credentials.py +140 -0
- letta/data_sources/connectors.py +247 -0
- letta/embeddings.py +218 -0
- letta/errors.py +26 -0
- letta/functions/__init__.py +0 -0
- letta/functions/function_sets/base.py +174 -0
- letta/functions/function_sets/extras.py +132 -0
- letta/functions/functions.py +105 -0
- letta/functions/schema_generator.py +205 -0
- letta/humans/__init__.py +0 -0
- letta/humans/examples/basic.txt +1 -0
- letta/humans/examples/cs_phd.txt +9 -0
- letta/interface.py +314 -0
- letta/llm_api/__init__.py +0 -0
- letta/llm_api/anthropic.py +383 -0
- letta/llm_api/azure_openai.py +155 -0
- letta/llm_api/cohere.py +396 -0
- letta/llm_api/google_ai.py +468 -0
- letta/llm_api/llm_api_tools.py +485 -0
- letta/llm_api/openai.py +470 -0
- letta/local_llm/README.md +3 -0
- letta/local_llm/__init__.py +0 -0
- letta/local_llm/chat_completion_proxy.py +279 -0
- letta/local_llm/constants.py +31 -0
- letta/local_llm/function_parser.py +68 -0
- letta/local_llm/grammars/__init__.py +0 -0
- letta/local_llm/grammars/gbnf_grammar_generator.py +1324 -0
- letta/local_llm/grammars/json.gbnf +26 -0
- letta/local_llm/grammars/json_func_calls_with_inner_thoughts.gbnf +32 -0
- letta/local_llm/groq/api.py +97 -0
- letta/local_llm/json_parser.py +202 -0
- letta/local_llm/koboldcpp/api.py +62 -0
- letta/local_llm/koboldcpp/settings.py +23 -0
- letta/local_llm/llamacpp/api.py +58 -0
- letta/local_llm/llamacpp/settings.py +22 -0
- letta/local_llm/llm_chat_completion_wrappers/__init__.py +0 -0
- letta/local_llm/llm_chat_completion_wrappers/airoboros.py +452 -0
- letta/local_llm/llm_chat_completion_wrappers/chatml.py +470 -0
- letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +387 -0
- letta/local_llm/llm_chat_completion_wrappers/dolphin.py +246 -0
- letta/local_llm/llm_chat_completion_wrappers/llama3.py +345 -0
- letta/local_llm/llm_chat_completion_wrappers/simple_summary_wrapper.py +156 -0
- letta/local_llm/llm_chat_completion_wrappers/wrapper_base.py +11 -0
- letta/local_llm/llm_chat_completion_wrappers/zephyr.py +345 -0
- letta/local_llm/lmstudio/api.py +100 -0
- letta/local_llm/lmstudio/settings.py +29 -0
- letta/local_llm/ollama/api.py +88 -0
- letta/local_llm/ollama/settings.py +32 -0
- letta/local_llm/settings/__init__.py +0 -0
- letta/local_llm/settings/deterministic_mirostat.py +45 -0
- letta/local_llm/settings/settings.py +72 -0
- letta/local_llm/settings/simple.py +28 -0
- letta/local_llm/utils.py +265 -0
- letta/local_llm/vllm/api.py +63 -0
- letta/local_llm/webui/api.py +60 -0
- letta/local_llm/webui/legacy_api.py +58 -0
- letta/local_llm/webui/legacy_settings.py +23 -0
- letta/local_llm/webui/settings.py +24 -0
- letta/log.py +76 -0
- letta/main.py +437 -0
- letta/memory.py +440 -0
- letta/metadata.py +884 -0
- letta/openai_backcompat/__init__.py +0 -0
- letta/openai_backcompat/openai_object.py +437 -0
- letta/persistence_manager.py +148 -0
- letta/personas/__init__.py +0 -0
- letta/personas/examples/anna_pa.txt +13 -0
- letta/personas/examples/google_search_persona.txt +15 -0
- letta/personas/examples/memgpt_doc.txt +6 -0
- letta/personas/examples/memgpt_starter.txt +4 -0
- letta/personas/examples/sam.txt +14 -0
- letta/personas/examples/sam_pov.txt +14 -0
- letta/personas/examples/sam_simple_pov_gpt35.txt +13 -0
- letta/personas/examples/sqldb/test.db +0 -0
- letta/prompts/__init__.py +0 -0
- letta/prompts/gpt_summarize.py +14 -0
- letta/prompts/gpt_system.py +26 -0
- letta/prompts/system/memgpt_base.txt +49 -0
- letta/prompts/system/memgpt_chat.txt +58 -0
- letta/prompts/system/memgpt_chat_compressed.txt +13 -0
- letta/prompts/system/memgpt_chat_fstring.txt +51 -0
- letta/prompts/system/memgpt_doc.txt +50 -0
- letta/prompts/system/memgpt_gpt35_extralong.txt +53 -0
- letta/prompts/system/memgpt_intuitive_knowledge.txt +31 -0
- letta/prompts/system/memgpt_modified_chat.txt +23 -0
- letta/pytest.ini +0 -0
- letta/schemas/agent.py +117 -0
- letta/schemas/api_key.py +21 -0
- letta/schemas/block.py +135 -0
- letta/schemas/document.py +21 -0
- letta/schemas/embedding_config.py +54 -0
- letta/schemas/enums.py +35 -0
- letta/schemas/job.py +38 -0
- letta/schemas/letta_base.py +80 -0
- letta/schemas/letta_message.py +175 -0
- letta/schemas/letta_request.py +23 -0
- letta/schemas/letta_response.py +28 -0
- letta/schemas/llm_config.py +54 -0
- letta/schemas/memory.py +224 -0
- letta/schemas/message.py +727 -0
- letta/schemas/openai/chat_completion_request.py +123 -0
- letta/schemas/openai/chat_completion_response.py +136 -0
- letta/schemas/openai/chat_completions.py +123 -0
- letta/schemas/openai/embedding_response.py +11 -0
- letta/schemas/openai/openai.py +157 -0
- letta/schemas/organization.py +20 -0
- letta/schemas/passage.py +80 -0
- letta/schemas/source.py +62 -0
- letta/schemas/tool.py +143 -0
- letta/schemas/usage.py +18 -0
- letta/schemas/user.py +33 -0
- letta/server/__init__.py +0 -0
- letta/server/constants.py +6 -0
- letta/server/rest_api/__init__.py +0 -0
- letta/server/rest_api/admin/__init__.py +0 -0
- letta/server/rest_api/admin/agents.py +21 -0
- letta/server/rest_api/admin/tools.py +83 -0
- letta/server/rest_api/admin/users.py +98 -0
- letta/server/rest_api/app.py +193 -0
- letta/server/rest_api/auth/__init__.py +0 -0
- letta/server/rest_api/auth/index.py +43 -0
- letta/server/rest_api/auth_token.py +22 -0
- letta/server/rest_api/interface.py +726 -0
- letta/server/rest_api/routers/__init__.py +0 -0
- letta/server/rest_api/routers/openai/__init__.py +0 -0
- letta/server/rest_api/routers/openai/assistants/__init__.py +0 -0
- letta/server/rest_api/routers/openai/assistants/assistants.py +115 -0
- letta/server/rest_api/routers/openai/assistants/schemas.py +121 -0
- letta/server/rest_api/routers/openai/assistants/threads.py +336 -0
- letta/server/rest_api/routers/openai/chat_completions/__init__.py +0 -0
- letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +131 -0
- letta/server/rest_api/routers/v1/__init__.py +15 -0
- letta/server/rest_api/routers/v1/agents.py +543 -0
- letta/server/rest_api/routers/v1/blocks.py +73 -0
- letta/server/rest_api/routers/v1/jobs.py +46 -0
- letta/server/rest_api/routers/v1/llms.py +28 -0
- letta/server/rest_api/routers/v1/organizations.py +61 -0
- letta/server/rest_api/routers/v1/sources.py +199 -0
- letta/server/rest_api/routers/v1/tools.py +103 -0
- letta/server/rest_api/routers/v1/users.py +109 -0
- letta/server/rest_api/static_files.py +74 -0
- letta/server/rest_api/utils.py +69 -0
- letta/server/server.py +1995 -0
- letta/server/startup.sh +8 -0
- letta/server/static_files/assets/index-0cbf7ad5.js +274 -0
- letta/server/static_files/assets/index-156816da.css +1 -0
- letta/server/static_files/assets/index-486e3228.js +274 -0
- letta/server/static_files/favicon.ico +0 -0
- letta/server/static_files/index.html +39 -0
- letta/server/static_files/memgpt_logo_transparent.png +0 -0
- letta/server/utils.py +46 -0
- letta/server/ws_api/__init__.py +0 -0
- letta/server/ws_api/example_client.py +104 -0
- letta/server/ws_api/interface.py +108 -0
- letta/server/ws_api/protocol.py +100 -0
- letta/server/ws_api/server.py +145 -0
- letta/settings.py +165 -0
- letta/streaming_interface.py +396 -0
- letta/system.py +207 -0
- letta/utils.py +1065 -0
- letta_nightly-0.1.7.dev20240924104148.dist-info/LICENSE +190 -0
- letta_nightly-0.1.7.dev20240924104148.dist-info/METADATA +98 -0
- letta_nightly-0.1.7.dev20240924104148.dist-info/RECORD +189 -0
- letta_nightly-0.1.7.dev20240924104148.dist-info/WHEEL +4 -0
- letta_nightly-0.1.7.dev20240924104148.dist-info/entry_points.txt +3 -0
letta/main.py
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import traceback
|
|
4
|
+
|
|
5
|
+
import questionary
|
|
6
|
+
import requests
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
|
|
10
|
+
import letta.agent as agent
|
|
11
|
+
import letta.errors as errors
|
|
12
|
+
import letta.system as system
|
|
13
|
+
|
|
14
|
+
# import benchmark
|
|
15
|
+
from letta import create_client
|
|
16
|
+
from letta.benchmark.benchmark import bench
|
|
17
|
+
from letta.cli.cli import delete_agent, open_folder, quickstart, run, server, version
|
|
18
|
+
from letta.cli.cli_config import add, add_tool, configure, delete, list, list_tools
|
|
19
|
+
from letta.cli.cli_load import app as load_app
|
|
20
|
+
from letta.config import LettaConfig
|
|
21
|
+
from letta.constants import FUNC_FAILED_HEARTBEAT_MESSAGE, REQ_HEARTBEAT_MESSAGE
|
|
22
|
+
from letta.metadata import MetadataStore
|
|
23
|
+
from letta.schemas.enums import OptionState
|
|
24
|
+
|
|
25
|
+
# from letta.interface import CLIInterface as interface # for printing to terminal
|
|
26
|
+
from letta.streaming_interface import AgentRefreshStreamingInterface
|
|
27
|
+
|
|
28
|
+
# interface = interface()
|
|
29
|
+
|
|
30
|
+
app = typer.Typer(pretty_exceptions_enable=False)
|
|
31
|
+
app.command(name="run")(run)
|
|
32
|
+
app.command(name="version")(version)
|
|
33
|
+
app.command(name="configure")(configure)
|
|
34
|
+
app.command(name="list")(list)
|
|
35
|
+
app.command(name="add")(add)
|
|
36
|
+
app.command(name="add-tool")(add_tool)
|
|
37
|
+
app.command(name="list-tools")(list_tools)
|
|
38
|
+
app.command(name="delete")(delete)
|
|
39
|
+
app.command(name="server")(server)
|
|
40
|
+
app.command(name="folder")(open_folder)
|
|
41
|
+
app.command(name="quickstart")(quickstart)
|
|
42
|
+
# load data commands
|
|
43
|
+
app.add_typer(load_app, name="load")
|
|
44
|
+
# benchmark command
|
|
45
|
+
app.command(name="benchmark")(bench)
|
|
46
|
+
# delete agents
|
|
47
|
+
app.command(name="delete-agent")(delete_agent)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def clear_line(console, strip_ui=False):
|
|
51
|
+
if strip_ui:
|
|
52
|
+
return
|
|
53
|
+
if os.name == "nt": # for windows
|
|
54
|
+
console.print("\033[A\033[K", end="")
|
|
55
|
+
else: # for linux
|
|
56
|
+
sys.stdout.write("\033[2K\033[G")
|
|
57
|
+
sys.stdout.flush()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def run_agent_loop(
|
|
61
|
+
letta_agent: agent.Agent,
|
|
62
|
+
config: LettaConfig,
|
|
63
|
+
first: bool,
|
|
64
|
+
ms: MetadataStore,
|
|
65
|
+
no_verify: bool = False,
|
|
66
|
+
strip_ui: bool = False,
|
|
67
|
+
stream: bool = False,
|
|
68
|
+
inner_thoughts_in_kwargs: OptionState = OptionState.DEFAULT,
|
|
69
|
+
):
|
|
70
|
+
if isinstance(letta_agent.interface, AgentRefreshStreamingInterface):
|
|
71
|
+
# letta_agent.interface.toggle_streaming(on=stream)
|
|
72
|
+
if not stream:
|
|
73
|
+
letta_agent.interface = letta_agent.interface.nonstreaming_interface
|
|
74
|
+
|
|
75
|
+
if hasattr(letta_agent.interface, "console"):
|
|
76
|
+
console = letta_agent.interface.console
|
|
77
|
+
else:
|
|
78
|
+
console = Console()
|
|
79
|
+
|
|
80
|
+
counter = 0
|
|
81
|
+
user_input = None
|
|
82
|
+
skip_next_user_input = False
|
|
83
|
+
user_message = None
|
|
84
|
+
USER_GOES_FIRST = first
|
|
85
|
+
|
|
86
|
+
if not USER_GOES_FIRST:
|
|
87
|
+
console.input("[bold cyan]Hit enter to begin (will request first Letta message)[/bold cyan]\n")
|
|
88
|
+
clear_line(console, strip_ui=strip_ui)
|
|
89
|
+
print()
|
|
90
|
+
|
|
91
|
+
multiline_input = False
|
|
92
|
+
|
|
93
|
+
# create client
|
|
94
|
+
client = create_client()
|
|
95
|
+
ms = MetadataStore(config) # TODO: remove
|
|
96
|
+
|
|
97
|
+
# run loops
|
|
98
|
+
while True:
|
|
99
|
+
if not skip_next_user_input and (counter > 0 or USER_GOES_FIRST):
|
|
100
|
+
# Ask for user input
|
|
101
|
+
if not stream:
|
|
102
|
+
print()
|
|
103
|
+
user_input = questionary.text(
|
|
104
|
+
"Enter your message:",
|
|
105
|
+
multiline=multiline_input,
|
|
106
|
+
qmark=">",
|
|
107
|
+
).ask()
|
|
108
|
+
clear_line(console, strip_ui=strip_ui)
|
|
109
|
+
if not stream:
|
|
110
|
+
print()
|
|
111
|
+
|
|
112
|
+
# Gracefully exit on Ctrl-C/D
|
|
113
|
+
if user_input is None:
|
|
114
|
+
user_input = "/exit"
|
|
115
|
+
|
|
116
|
+
user_input = user_input.rstrip()
|
|
117
|
+
|
|
118
|
+
if user_input.startswith("!"):
|
|
119
|
+
print(f"Commands for CLI begin with '/' not '!'")
|
|
120
|
+
continue
|
|
121
|
+
|
|
122
|
+
if user_input == "":
|
|
123
|
+
# no empty messages allowed
|
|
124
|
+
print("Empty input received. Try again!")
|
|
125
|
+
continue
|
|
126
|
+
|
|
127
|
+
# Handle CLI commands
|
|
128
|
+
# Commands to not get passed as input to Letta
|
|
129
|
+
if user_input.startswith("/"):
|
|
130
|
+
# updated agent save functions
|
|
131
|
+
if user_input.lower() == "/exit":
|
|
132
|
+
# letta_agent.save()
|
|
133
|
+
agent.save_agent(letta_agent, ms)
|
|
134
|
+
break
|
|
135
|
+
elif user_input.lower() == "/save" or user_input.lower() == "/savechat":
|
|
136
|
+
# letta_agent.save()
|
|
137
|
+
agent.save_agent(letta_agent, ms)
|
|
138
|
+
continue
|
|
139
|
+
elif user_input.lower() == "/attach":
|
|
140
|
+
# TODO: check if agent already has it
|
|
141
|
+
|
|
142
|
+
# TODO: check to ensure source embedding dimentions/model match agents, and disallow attachment if not
|
|
143
|
+
# TODO: alternatively, only list sources with compatible embeddings, and print warning about non-compatible sources
|
|
144
|
+
|
|
145
|
+
sources = client.list_sources()
|
|
146
|
+
if len(sources) == 0:
|
|
147
|
+
typer.secho(
|
|
148
|
+
'No sources available. You must load a souce with "letta load ..." before running /attach.',
|
|
149
|
+
fg=typer.colors.RED,
|
|
150
|
+
bold=True,
|
|
151
|
+
)
|
|
152
|
+
continue
|
|
153
|
+
|
|
154
|
+
# determine what sources are valid to be attached to this agent
|
|
155
|
+
valid_options = []
|
|
156
|
+
invalid_options = []
|
|
157
|
+
for source in sources:
|
|
158
|
+
if source.embedding_config == letta_agent.agent_state.embedding_config:
|
|
159
|
+
valid_options.append(source.name)
|
|
160
|
+
else:
|
|
161
|
+
# print warning about invalid sources
|
|
162
|
+
typer.secho(
|
|
163
|
+
f"Source {source.name} exists but has embedding dimentions {source.embedding_dim} from model {source.embedding_model}, while the agent uses embedding dimentions {letta_agent.agent_state.embedding_config.embedding_dim} and model {letta_agent.agent_state.embedding_config.embedding_model}",
|
|
164
|
+
fg=typer.colors.YELLOW,
|
|
165
|
+
)
|
|
166
|
+
invalid_options.append(source.name)
|
|
167
|
+
|
|
168
|
+
# prompt user for data source selection
|
|
169
|
+
data_source = questionary.select("Select data source", choices=valid_options).ask()
|
|
170
|
+
|
|
171
|
+
# attach new data
|
|
172
|
+
client.attach_source_to_agent(agent_id=letta_agent.agent_state.id, source_name=data_source)
|
|
173
|
+
|
|
174
|
+
continue
|
|
175
|
+
|
|
176
|
+
elif user_input.lower() == "/dump" or user_input.lower().startswith("/dump "):
|
|
177
|
+
# Check if there's an additional argument that's an integer
|
|
178
|
+
command = user_input.strip().split()
|
|
179
|
+
amount = int(command[1]) if len(command) > 1 and command[1].isdigit() else 0
|
|
180
|
+
if amount == 0:
|
|
181
|
+
letta_agent.interface.print_messages(letta_agent._messages, dump=True)
|
|
182
|
+
else:
|
|
183
|
+
letta_agent.interface.print_messages(letta_agent._messages[-min(amount, len(letta_agent.messages)) :], dump=True)
|
|
184
|
+
continue
|
|
185
|
+
|
|
186
|
+
elif user_input.lower() == "/dumpraw":
|
|
187
|
+
letta_agent.interface.print_messages_raw(letta_agent._messages)
|
|
188
|
+
continue
|
|
189
|
+
|
|
190
|
+
elif user_input.lower() == "/memory":
|
|
191
|
+
print(f"\nDumping memory contents:\n")
|
|
192
|
+
print(f"{letta_agent.memory.compile()}")
|
|
193
|
+
print(f"{letta_agent.persistence_manager.archival_memory.compile()}")
|
|
194
|
+
print(f"{letta_agent.persistence_manager.recall_memory.compile()}")
|
|
195
|
+
continue
|
|
196
|
+
|
|
197
|
+
elif user_input.lower() == "/model":
|
|
198
|
+
print(f"Current model: {letta_agent.agent_state.llm_config.model}")
|
|
199
|
+
continue
|
|
200
|
+
|
|
201
|
+
elif user_input.lower() == "/pop" or user_input.lower().startswith("/pop "):
|
|
202
|
+
# Check if there's an additional argument that's an integer
|
|
203
|
+
command = user_input.strip().split()
|
|
204
|
+
pop_amount = int(command[1]) if len(command) > 1 and command[1].isdigit() else 3
|
|
205
|
+
try:
|
|
206
|
+
popped_messages = letta_agent.pop_message(count=pop_amount)
|
|
207
|
+
except ValueError as e:
|
|
208
|
+
print(f"Error popping messages: {e}")
|
|
209
|
+
continue
|
|
210
|
+
|
|
211
|
+
elif user_input.lower() == "/retry":
|
|
212
|
+
print(f"Retrying for another answer...")
|
|
213
|
+
try:
|
|
214
|
+
letta_agent.retry_message()
|
|
215
|
+
except Exception as e:
|
|
216
|
+
print(f"Error retrying message: {e}")
|
|
217
|
+
continue
|
|
218
|
+
|
|
219
|
+
elif user_input.lower() == "/rethink" or user_input.lower().startswith("/rethink "):
|
|
220
|
+
if len(user_input) < len("/rethink "):
|
|
221
|
+
print("Missing text after the command")
|
|
222
|
+
continue
|
|
223
|
+
try:
|
|
224
|
+
letta_agent.rethink_message(new_thought=user_input[len("/rethink ") :].strip())
|
|
225
|
+
except Exception as e:
|
|
226
|
+
print(f"Error rethinking message: {e}")
|
|
227
|
+
continue
|
|
228
|
+
|
|
229
|
+
elif user_input.lower() == "/rewrite" or user_input.lower().startswith("/rewrite "):
|
|
230
|
+
if len(user_input) < len("/rewrite "):
|
|
231
|
+
print("Missing text after the command")
|
|
232
|
+
continue
|
|
233
|
+
|
|
234
|
+
text = user_input[len("/rewrite ") :].strip()
|
|
235
|
+
try:
|
|
236
|
+
letta_agent.rewrite_message(new_text=text)
|
|
237
|
+
except Exception as e:
|
|
238
|
+
print(f"Error rewriting message: {e}")
|
|
239
|
+
continue
|
|
240
|
+
|
|
241
|
+
elif user_input.lower() == "/summarize":
|
|
242
|
+
try:
|
|
243
|
+
letta_agent.summarize_messages_inplace()
|
|
244
|
+
typer.secho(
|
|
245
|
+
f"/summarize succeeded",
|
|
246
|
+
fg=typer.colors.GREEN,
|
|
247
|
+
bold=True,
|
|
248
|
+
)
|
|
249
|
+
except (errors.LLMError, requests.exceptions.HTTPError) as e:
|
|
250
|
+
typer.secho(
|
|
251
|
+
f"/summarize failed:\n{e}",
|
|
252
|
+
fg=typer.colors.RED,
|
|
253
|
+
bold=True,
|
|
254
|
+
)
|
|
255
|
+
continue
|
|
256
|
+
|
|
257
|
+
elif user_input.lower().startswith("/add_function"):
|
|
258
|
+
try:
|
|
259
|
+
if len(user_input) < len("/add_function "):
|
|
260
|
+
print("Missing function name after the command")
|
|
261
|
+
continue
|
|
262
|
+
function_name = user_input[len("/add_function ") :].strip()
|
|
263
|
+
result = letta_agent.add_function(function_name)
|
|
264
|
+
typer.secho(
|
|
265
|
+
f"/add_function succeeded: {result}",
|
|
266
|
+
fg=typer.colors.GREEN,
|
|
267
|
+
bold=True,
|
|
268
|
+
)
|
|
269
|
+
except ValueError as e:
|
|
270
|
+
typer.secho(
|
|
271
|
+
f"/add_function failed:\n{e}",
|
|
272
|
+
fg=typer.colors.RED,
|
|
273
|
+
bold=True,
|
|
274
|
+
)
|
|
275
|
+
continue
|
|
276
|
+
elif user_input.lower().startswith("/remove_function"):
|
|
277
|
+
try:
|
|
278
|
+
if len(user_input) < len("/remove_function "):
|
|
279
|
+
print("Missing function name after the command")
|
|
280
|
+
continue
|
|
281
|
+
function_name = user_input[len("/remove_function ") :].strip()
|
|
282
|
+
result = letta_agent.remove_function(function_name)
|
|
283
|
+
typer.secho(
|
|
284
|
+
f"/remove_function succeeded: {result}",
|
|
285
|
+
fg=typer.colors.GREEN,
|
|
286
|
+
bold=True,
|
|
287
|
+
)
|
|
288
|
+
except ValueError as e:
|
|
289
|
+
typer.secho(
|
|
290
|
+
f"/remove_function failed:\n{e}",
|
|
291
|
+
fg=typer.colors.RED,
|
|
292
|
+
bold=True,
|
|
293
|
+
)
|
|
294
|
+
continue
|
|
295
|
+
|
|
296
|
+
# No skip options
|
|
297
|
+
elif user_input.lower() == "/wipe":
|
|
298
|
+
letta_agent = agent.Agent(letta_agent.interface)
|
|
299
|
+
user_message = None
|
|
300
|
+
|
|
301
|
+
elif user_input.lower() == "/heartbeat":
|
|
302
|
+
user_message = system.get_heartbeat()
|
|
303
|
+
|
|
304
|
+
elif user_input.lower() == "/memorywarning":
|
|
305
|
+
user_message = system.get_token_limit_warning()
|
|
306
|
+
|
|
307
|
+
elif user_input.lower() == "//":
|
|
308
|
+
multiline_input = not multiline_input
|
|
309
|
+
continue
|
|
310
|
+
|
|
311
|
+
elif user_input.lower() == "/" or user_input.lower() == "/help":
|
|
312
|
+
questionary.print("CLI commands", "bold")
|
|
313
|
+
for cmd, desc in USER_COMMANDS:
|
|
314
|
+
questionary.print(cmd, "bold")
|
|
315
|
+
questionary.print(f" {desc}")
|
|
316
|
+
continue
|
|
317
|
+
|
|
318
|
+
elif user_input.lower().startswith("/systemswap"):
|
|
319
|
+
if len(user_input) < len("/systemswap "):
|
|
320
|
+
print("Missing new system prompt after the command")
|
|
321
|
+
continue
|
|
322
|
+
old_system_prompt = letta_agent.system
|
|
323
|
+
new_system_prompt = user_input[len("/systemswap ") :].strip()
|
|
324
|
+
|
|
325
|
+
# Show warning and prompts to user
|
|
326
|
+
typer.secho(
|
|
327
|
+
"\nWARNING: You are about to change the system prompt.",
|
|
328
|
+
# fg=typer.colors.BRIGHT_YELLOW,
|
|
329
|
+
bold=True,
|
|
330
|
+
)
|
|
331
|
+
typer.secho(
|
|
332
|
+
f"\nOld system prompt:\n{old_system_prompt}",
|
|
333
|
+
fg=typer.colors.RED,
|
|
334
|
+
bold=True,
|
|
335
|
+
)
|
|
336
|
+
typer.secho(
|
|
337
|
+
f"\nNew system prompt:\n{new_system_prompt}",
|
|
338
|
+
fg=typer.colors.GREEN,
|
|
339
|
+
bold=True,
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
# Ask for confirmation
|
|
343
|
+
confirm = questionary.confirm("Do you want to proceed with the swap?").ask()
|
|
344
|
+
|
|
345
|
+
if confirm:
|
|
346
|
+
letta_agent.update_system_prompt(new_system_prompt=new_system_prompt)
|
|
347
|
+
print("System prompt updated successfully.")
|
|
348
|
+
else:
|
|
349
|
+
print("System prompt swap cancelled.")
|
|
350
|
+
|
|
351
|
+
continue
|
|
352
|
+
|
|
353
|
+
else:
|
|
354
|
+
print(f"Unrecognized command: {user_input}")
|
|
355
|
+
continue
|
|
356
|
+
|
|
357
|
+
else:
|
|
358
|
+
# If message did not begin with command prefix, pass inputs to Letta
|
|
359
|
+
# Handle user message and append to messages
|
|
360
|
+
user_message = system.package_user_message(user_input)
|
|
361
|
+
|
|
362
|
+
skip_next_user_input = False
|
|
363
|
+
|
|
364
|
+
def process_agent_step(user_message, no_verify):
|
|
365
|
+
step_response = letta_agent.step(
|
|
366
|
+
user_message,
|
|
367
|
+
first_message=False,
|
|
368
|
+
skip_verify=no_verify,
|
|
369
|
+
stream=stream,
|
|
370
|
+
inner_thoughts_in_kwargs=inner_thoughts_in_kwargs,
|
|
371
|
+
ms=ms,
|
|
372
|
+
)
|
|
373
|
+
new_messages = step_response.messages
|
|
374
|
+
heartbeat_request = step_response.heartbeat_request
|
|
375
|
+
function_failed = step_response.function_failed
|
|
376
|
+
token_warning = step_response.in_context_memory_warning
|
|
377
|
+
step_response.usage
|
|
378
|
+
|
|
379
|
+
agent.save_agent(letta_agent, ms)
|
|
380
|
+
skip_next_user_input = False
|
|
381
|
+
if token_warning:
|
|
382
|
+
user_message = system.get_token_limit_warning()
|
|
383
|
+
skip_next_user_input = True
|
|
384
|
+
elif function_failed:
|
|
385
|
+
user_message = system.get_heartbeat(FUNC_FAILED_HEARTBEAT_MESSAGE)
|
|
386
|
+
skip_next_user_input = True
|
|
387
|
+
elif heartbeat_request:
|
|
388
|
+
user_message = system.get_heartbeat(REQ_HEARTBEAT_MESSAGE)
|
|
389
|
+
skip_next_user_input = True
|
|
390
|
+
|
|
391
|
+
return new_messages, user_message, skip_next_user_input
|
|
392
|
+
|
|
393
|
+
while True:
|
|
394
|
+
try:
|
|
395
|
+
if strip_ui:
|
|
396
|
+
new_messages, user_message, skip_next_user_input = process_agent_step(user_message, no_verify)
|
|
397
|
+
break
|
|
398
|
+
else:
|
|
399
|
+
if stream:
|
|
400
|
+
# Don't display the "Thinking..." if streaming
|
|
401
|
+
new_messages, user_message, skip_next_user_input = process_agent_step(user_message, no_verify)
|
|
402
|
+
else:
|
|
403
|
+
with console.status("[bold cyan]Thinking...") as status:
|
|
404
|
+
new_messages, user_message, skip_next_user_input = process_agent_step(user_message, no_verify)
|
|
405
|
+
break
|
|
406
|
+
except KeyboardInterrupt:
|
|
407
|
+
print("User interrupt occurred.")
|
|
408
|
+
retry = questionary.confirm("Retry agent.step()?").ask()
|
|
409
|
+
if not retry:
|
|
410
|
+
break
|
|
411
|
+
except Exception:
|
|
412
|
+
print("An exception occurred when running agent.step(): ")
|
|
413
|
+
traceback.print_exc()
|
|
414
|
+
retry = questionary.confirm("Retry agent.step()?").ask()
|
|
415
|
+
if not retry:
|
|
416
|
+
break
|
|
417
|
+
|
|
418
|
+
counter += 1
|
|
419
|
+
|
|
420
|
+
print("Finished.")
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
USER_COMMANDS = [
|
|
424
|
+
("//", "toggle multiline input mode"),
|
|
425
|
+
("/exit", "exit the CLI"),
|
|
426
|
+
("/save", "save a checkpoint of the current agent/conversation state"),
|
|
427
|
+
("/load", "load a saved checkpoint"),
|
|
428
|
+
("/dump <count>", "view the last <count> messages (all if <count> is omitted)"),
|
|
429
|
+
("/memory", "print the current contents of agent memory"),
|
|
430
|
+
("/pop <count>", "undo <count> messages in the conversation (default is 3)"),
|
|
431
|
+
("/retry", "pops the last answer and tries to get another one"),
|
|
432
|
+
("/rethink <text>", "changes the inner thoughts of the last agent message"),
|
|
433
|
+
("/rewrite <text>", "changes the reply of the last agent message"),
|
|
434
|
+
("/heartbeat", "send a heartbeat system message to the agent"),
|
|
435
|
+
("/memorywarning", "send a memory warning system message to the agent"),
|
|
436
|
+
("/attach", "attach data source to agent"),
|
|
437
|
+
]
|