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.

Files changed (189) hide show
  1. letta/__init__.py +24 -0
  2. letta/__main__.py +3 -0
  3. letta/agent.py +1427 -0
  4. letta/agent_store/chroma.py +295 -0
  5. letta/agent_store/db.py +546 -0
  6. letta/agent_store/lancedb.py +177 -0
  7. letta/agent_store/milvus.py +198 -0
  8. letta/agent_store/qdrant.py +201 -0
  9. letta/agent_store/storage.py +188 -0
  10. letta/benchmark/benchmark.py +96 -0
  11. letta/benchmark/constants.py +14 -0
  12. letta/cli/cli.py +689 -0
  13. letta/cli/cli_config.py +1282 -0
  14. letta/cli/cli_load.py +166 -0
  15. letta/client/__init__.py +0 -0
  16. letta/client/admin.py +171 -0
  17. letta/client/client.py +2360 -0
  18. letta/client/streaming.py +90 -0
  19. letta/client/utils.py +61 -0
  20. letta/config.py +484 -0
  21. letta/configs/anthropic.json +13 -0
  22. letta/configs/letta_hosted.json +11 -0
  23. letta/configs/openai.json +12 -0
  24. letta/constants.py +134 -0
  25. letta/credentials.py +140 -0
  26. letta/data_sources/connectors.py +247 -0
  27. letta/embeddings.py +218 -0
  28. letta/errors.py +26 -0
  29. letta/functions/__init__.py +0 -0
  30. letta/functions/function_sets/base.py +174 -0
  31. letta/functions/function_sets/extras.py +132 -0
  32. letta/functions/functions.py +105 -0
  33. letta/functions/schema_generator.py +205 -0
  34. letta/humans/__init__.py +0 -0
  35. letta/humans/examples/basic.txt +1 -0
  36. letta/humans/examples/cs_phd.txt +9 -0
  37. letta/interface.py +314 -0
  38. letta/llm_api/__init__.py +0 -0
  39. letta/llm_api/anthropic.py +383 -0
  40. letta/llm_api/azure_openai.py +155 -0
  41. letta/llm_api/cohere.py +396 -0
  42. letta/llm_api/google_ai.py +468 -0
  43. letta/llm_api/llm_api_tools.py +485 -0
  44. letta/llm_api/openai.py +470 -0
  45. letta/local_llm/README.md +3 -0
  46. letta/local_llm/__init__.py +0 -0
  47. letta/local_llm/chat_completion_proxy.py +279 -0
  48. letta/local_llm/constants.py +31 -0
  49. letta/local_llm/function_parser.py +68 -0
  50. letta/local_llm/grammars/__init__.py +0 -0
  51. letta/local_llm/grammars/gbnf_grammar_generator.py +1324 -0
  52. letta/local_llm/grammars/json.gbnf +26 -0
  53. letta/local_llm/grammars/json_func_calls_with_inner_thoughts.gbnf +32 -0
  54. letta/local_llm/groq/api.py +97 -0
  55. letta/local_llm/json_parser.py +202 -0
  56. letta/local_llm/koboldcpp/api.py +62 -0
  57. letta/local_llm/koboldcpp/settings.py +23 -0
  58. letta/local_llm/llamacpp/api.py +58 -0
  59. letta/local_llm/llamacpp/settings.py +22 -0
  60. letta/local_llm/llm_chat_completion_wrappers/__init__.py +0 -0
  61. letta/local_llm/llm_chat_completion_wrappers/airoboros.py +452 -0
  62. letta/local_llm/llm_chat_completion_wrappers/chatml.py +470 -0
  63. letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +387 -0
  64. letta/local_llm/llm_chat_completion_wrappers/dolphin.py +246 -0
  65. letta/local_llm/llm_chat_completion_wrappers/llama3.py +345 -0
  66. letta/local_llm/llm_chat_completion_wrappers/simple_summary_wrapper.py +156 -0
  67. letta/local_llm/llm_chat_completion_wrappers/wrapper_base.py +11 -0
  68. letta/local_llm/llm_chat_completion_wrappers/zephyr.py +345 -0
  69. letta/local_llm/lmstudio/api.py +100 -0
  70. letta/local_llm/lmstudio/settings.py +29 -0
  71. letta/local_llm/ollama/api.py +88 -0
  72. letta/local_llm/ollama/settings.py +32 -0
  73. letta/local_llm/settings/__init__.py +0 -0
  74. letta/local_llm/settings/deterministic_mirostat.py +45 -0
  75. letta/local_llm/settings/settings.py +72 -0
  76. letta/local_llm/settings/simple.py +28 -0
  77. letta/local_llm/utils.py +265 -0
  78. letta/local_llm/vllm/api.py +63 -0
  79. letta/local_llm/webui/api.py +60 -0
  80. letta/local_llm/webui/legacy_api.py +58 -0
  81. letta/local_llm/webui/legacy_settings.py +23 -0
  82. letta/local_llm/webui/settings.py +24 -0
  83. letta/log.py +76 -0
  84. letta/main.py +437 -0
  85. letta/memory.py +440 -0
  86. letta/metadata.py +884 -0
  87. letta/openai_backcompat/__init__.py +0 -0
  88. letta/openai_backcompat/openai_object.py +437 -0
  89. letta/persistence_manager.py +148 -0
  90. letta/personas/__init__.py +0 -0
  91. letta/personas/examples/anna_pa.txt +13 -0
  92. letta/personas/examples/google_search_persona.txt +15 -0
  93. letta/personas/examples/memgpt_doc.txt +6 -0
  94. letta/personas/examples/memgpt_starter.txt +4 -0
  95. letta/personas/examples/sam.txt +14 -0
  96. letta/personas/examples/sam_pov.txt +14 -0
  97. letta/personas/examples/sam_simple_pov_gpt35.txt +13 -0
  98. letta/personas/examples/sqldb/test.db +0 -0
  99. letta/prompts/__init__.py +0 -0
  100. letta/prompts/gpt_summarize.py +14 -0
  101. letta/prompts/gpt_system.py +26 -0
  102. letta/prompts/system/memgpt_base.txt +49 -0
  103. letta/prompts/system/memgpt_chat.txt +58 -0
  104. letta/prompts/system/memgpt_chat_compressed.txt +13 -0
  105. letta/prompts/system/memgpt_chat_fstring.txt +51 -0
  106. letta/prompts/system/memgpt_doc.txt +50 -0
  107. letta/prompts/system/memgpt_gpt35_extralong.txt +53 -0
  108. letta/prompts/system/memgpt_intuitive_knowledge.txt +31 -0
  109. letta/prompts/system/memgpt_modified_chat.txt +23 -0
  110. letta/pytest.ini +0 -0
  111. letta/schemas/agent.py +117 -0
  112. letta/schemas/api_key.py +21 -0
  113. letta/schemas/block.py +135 -0
  114. letta/schemas/document.py +21 -0
  115. letta/schemas/embedding_config.py +54 -0
  116. letta/schemas/enums.py +35 -0
  117. letta/schemas/job.py +38 -0
  118. letta/schemas/letta_base.py +80 -0
  119. letta/schemas/letta_message.py +175 -0
  120. letta/schemas/letta_request.py +23 -0
  121. letta/schemas/letta_response.py +28 -0
  122. letta/schemas/llm_config.py +54 -0
  123. letta/schemas/memory.py +224 -0
  124. letta/schemas/message.py +727 -0
  125. letta/schemas/openai/chat_completion_request.py +123 -0
  126. letta/schemas/openai/chat_completion_response.py +136 -0
  127. letta/schemas/openai/chat_completions.py +123 -0
  128. letta/schemas/openai/embedding_response.py +11 -0
  129. letta/schemas/openai/openai.py +157 -0
  130. letta/schemas/organization.py +20 -0
  131. letta/schemas/passage.py +80 -0
  132. letta/schemas/source.py +62 -0
  133. letta/schemas/tool.py +143 -0
  134. letta/schemas/usage.py +18 -0
  135. letta/schemas/user.py +33 -0
  136. letta/server/__init__.py +0 -0
  137. letta/server/constants.py +6 -0
  138. letta/server/rest_api/__init__.py +0 -0
  139. letta/server/rest_api/admin/__init__.py +0 -0
  140. letta/server/rest_api/admin/agents.py +21 -0
  141. letta/server/rest_api/admin/tools.py +83 -0
  142. letta/server/rest_api/admin/users.py +98 -0
  143. letta/server/rest_api/app.py +193 -0
  144. letta/server/rest_api/auth/__init__.py +0 -0
  145. letta/server/rest_api/auth/index.py +43 -0
  146. letta/server/rest_api/auth_token.py +22 -0
  147. letta/server/rest_api/interface.py +726 -0
  148. letta/server/rest_api/routers/__init__.py +0 -0
  149. letta/server/rest_api/routers/openai/__init__.py +0 -0
  150. letta/server/rest_api/routers/openai/assistants/__init__.py +0 -0
  151. letta/server/rest_api/routers/openai/assistants/assistants.py +115 -0
  152. letta/server/rest_api/routers/openai/assistants/schemas.py +121 -0
  153. letta/server/rest_api/routers/openai/assistants/threads.py +336 -0
  154. letta/server/rest_api/routers/openai/chat_completions/__init__.py +0 -0
  155. letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +131 -0
  156. letta/server/rest_api/routers/v1/__init__.py +15 -0
  157. letta/server/rest_api/routers/v1/agents.py +543 -0
  158. letta/server/rest_api/routers/v1/blocks.py +73 -0
  159. letta/server/rest_api/routers/v1/jobs.py +46 -0
  160. letta/server/rest_api/routers/v1/llms.py +28 -0
  161. letta/server/rest_api/routers/v1/organizations.py +61 -0
  162. letta/server/rest_api/routers/v1/sources.py +199 -0
  163. letta/server/rest_api/routers/v1/tools.py +103 -0
  164. letta/server/rest_api/routers/v1/users.py +109 -0
  165. letta/server/rest_api/static_files.py +74 -0
  166. letta/server/rest_api/utils.py +69 -0
  167. letta/server/server.py +1995 -0
  168. letta/server/startup.sh +8 -0
  169. letta/server/static_files/assets/index-0cbf7ad5.js +274 -0
  170. letta/server/static_files/assets/index-156816da.css +1 -0
  171. letta/server/static_files/assets/index-486e3228.js +274 -0
  172. letta/server/static_files/favicon.ico +0 -0
  173. letta/server/static_files/index.html +39 -0
  174. letta/server/static_files/memgpt_logo_transparent.png +0 -0
  175. letta/server/utils.py +46 -0
  176. letta/server/ws_api/__init__.py +0 -0
  177. letta/server/ws_api/example_client.py +104 -0
  178. letta/server/ws_api/interface.py +108 -0
  179. letta/server/ws_api/protocol.py +100 -0
  180. letta/server/ws_api/server.py +145 -0
  181. letta/settings.py +165 -0
  182. letta/streaming_interface.py +396 -0
  183. letta/system.py +207 -0
  184. letta/utils.py +1065 -0
  185. letta_nightly-0.1.7.dev20240924104148.dist-info/LICENSE +190 -0
  186. letta_nightly-0.1.7.dev20240924104148.dist-info/METADATA +98 -0
  187. letta_nightly-0.1.7.dev20240924104148.dist-info/RECORD +189 -0
  188. letta_nightly-0.1.7.dev20240924104148.dist-info/WHEEL +4 -0
  189. 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
+ ]