letta-nightly 0.4.1.dev20241012104008__py3-none-any.whl → 0.4.1.dev20241014104152__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/agent.py +51 -65
- letta/local_llm/chat_completion_proxy.py +1 -3
- letta/main.py +19 -9
- letta/providers.py +22 -1
- letta/server/server.py +80 -17
- {letta_nightly-0.4.1.dev20241012104008.dist-info → letta_nightly-0.4.1.dev20241014104152.dist-info}/METADATA +1 -1
- {letta_nightly-0.4.1.dev20241012104008.dist-info → letta_nightly-0.4.1.dev20241014104152.dist-info}/RECORD +10 -10
- {letta_nightly-0.4.1.dev20241012104008.dist-info → letta_nightly-0.4.1.dev20241014104152.dist-info}/LICENSE +0 -0
- {letta_nightly-0.4.1.dev20241012104008.dist-info → letta_nightly-0.4.1.dev20241014104152.dist-info}/WHEEL +0 -0
- {letta_nightly-0.4.1.dev20241012104008.dist-info → letta_nightly-0.4.1.dev20241014104152.dist-info}/entry_points.txt +0 -0
letta/agent.py
CHANGED
|
@@ -39,6 +39,7 @@ from letta.system import (
|
|
|
39
39
|
get_login_event,
|
|
40
40
|
package_function_response,
|
|
41
41
|
package_summarize_message,
|
|
42
|
+
package_user_message,
|
|
42
43
|
)
|
|
43
44
|
from letta.utils import (
|
|
44
45
|
count_tokens,
|
|
@@ -200,16 +201,7 @@ class BaseAgent(ABC):
|
|
|
200
201
|
@abstractmethod
|
|
201
202
|
def step(
|
|
202
203
|
self,
|
|
203
|
-
messages: Union[Message, List[Message]
|
|
204
|
-
first_message: bool = False,
|
|
205
|
-
first_message_retry_limit: int = FIRST_MESSAGE_ATTEMPTS,
|
|
206
|
-
skip_verify: bool = False,
|
|
207
|
-
return_dicts: bool = True, # if True, return dicts, if False, return Message objects
|
|
208
|
-
recreate_message_timestamp: bool = True, # if True, when input is a Message type, recreated the 'created_at' field
|
|
209
|
-
stream: bool = False, # TODO move to config?
|
|
210
|
-
timestamp: Optional[datetime.datetime] = None,
|
|
211
|
-
inner_thoughts_in_kwargs_option: OptionState = OptionState.DEFAULT,
|
|
212
|
-
ms: Optional[MetadataStore] = None,
|
|
204
|
+
messages: Union[Message, List[Message]],
|
|
213
205
|
) -> AgentStepResponse:
|
|
214
206
|
"""
|
|
215
207
|
Top-level event message handler for the agent.
|
|
@@ -730,14 +722,13 @@ class Agent(BaseAgent):
|
|
|
730
722
|
|
|
731
723
|
def step(
|
|
732
724
|
self,
|
|
733
|
-
|
|
725
|
+
messages: Union[Message, List[Message]],
|
|
734
726
|
first_message: bool = False,
|
|
735
727
|
first_message_retry_limit: int = FIRST_MESSAGE_ATTEMPTS,
|
|
736
728
|
skip_verify: bool = False,
|
|
737
729
|
return_dicts: bool = True,
|
|
738
|
-
recreate_message_timestamp: bool = True, # if True, when input is a Message type, recreated the 'created_at' field
|
|
730
|
+
# recreate_message_timestamp: bool = True, # if True, when input is a Message type, recreated the 'created_at' field
|
|
739
731
|
stream: bool = False, # TODO move to config?
|
|
740
|
-
timestamp: Optional[datetime.datetime] = None,
|
|
741
732
|
inner_thoughts_in_kwargs_option: OptionState = OptionState.DEFAULT,
|
|
742
733
|
ms: Optional[MetadataStore] = None,
|
|
743
734
|
) -> AgentStepResponse:
|
|
@@ -760,50 +751,13 @@ class Agent(BaseAgent):
|
|
|
760
751
|
self.rebuild_memory(force=True, ms=ms)
|
|
761
752
|
|
|
762
753
|
# Step 1: add user message
|
|
763
|
-
if
|
|
764
|
-
|
|
765
|
-
assert user_message.text is not None
|
|
766
|
-
|
|
767
|
-
# Validate JSON via save/load
|
|
768
|
-
user_message_text = validate_json(user_message.text)
|
|
769
|
-
cleaned_user_message_text, name = strip_name_field_from_user_message(user_message_text)
|
|
770
|
-
|
|
771
|
-
if name is not None:
|
|
772
|
-
# Update Message object
|
|
773
|
-
user_message.text = cleaned_user_message_text
|
|
774
|
-
user_message.name = name
|
|
754
|
+
if isinstance(messages, Message):
|
|
755
|
+
messages = [messages]
|
|
775
756
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
user_message.created_at = get_utc_time()
|
|
757
|
+
if not all(isinstance(m, Message) for m in messages):
|
|
758
|
+
raise ValueError(f"messages should be a Message or a list of Message, got {type(messages)}")
|
|
779
759
|
|
|
780
|
-
|
|
781
|
-
# Validate JSON via save/load
|
|
782
|
-
user_message = validate_json(user_message)
|
|
783
|
-
cleaned_user_message_text, name = strip_name_field_from_user_message(user_message)
|
|
784
|
-
|
|
785
|
-
# If user_message['name'] is not None, it will be handled properly by dict_to_message
|
|
786
|
-
# So no need to run strip_name_field_from_user_message
|
|
787
|
-
|
|
788
|
-
# Create the associated Message object (in the database)
|
|
789
|
-
user_message = Message.dict_to_message(
|
|
790
|
-
agent_id=self.agent_state.id,
|
|
791
|
-
user_id=self.agent_state.user_id,
|
|
792
|
-
model=self.model,
|
|
793
|
-
openai_message_dict={"role": "user", "content": cleaned_user_message_text, "name": name},
|
|
794
|
-
created_at=timestamp,
|
|
795
|
-
)
|
|
796
|
-
|
|
797
|
-
else:
|
|
798
|
-
raise ValueError(f"Bad type for user_message: {type(user_message)}")
|
|
799
|
-
|
|
800
|
-
self.interface.user_message(user_message.text, msg_obj=user_message)
|
|
801
|
-
|
|
802
|
-
input_message_sequence = self._messages + [user_message]
|
|
803
|
-
|
|
804
|
-
# Alternatively, the requestor can send an empty user message
|
|
805
|
-
else:
|
|
806
|
-
input_message_sequence = self._messages
|
|
760
|
+
input_message_sequence = self._messages + messages
|
|
807
761
|
|
|
808
762
|
if len(input_message_sequence) > 1 and input_message_sequence[-1].role != "user":
|
|
809
763
|
printd(f"{CLI_WARNING_PREFIX}Attempting to run ChatCompletion without user as the last message in the queue")
|
|
@@ -846,11 +800,8 @@ class Agent(BaseAgent):
|
|
|
846
800
|
)
|
|
847
801
|
|
|
848
802
|
# Step 6: extend the message history
|
|
849
|
-
if
|
|
850
|
-
|
|
851
|
-
all_new_messages = [user_message] + all_response_messages
|
|
852
|
-
else:
|
|
853
|
-
raise ValueError(type(user_message))
|
|
803
|
+
if len(messages) > 0:
|
|
804
|
+
all_new_messages = messages + all_response_messages
|
|
854
805
|
else:
|
|
855
806
|
all_new_messages = all_response_messages
|
|
856
807
|
|
|
@@ -897,7 +848,7 @@ class Agent(BaseAgent):
|
|
|
897
848
|
)
|
|
898
849
|
|
|
899
850
|
except Exception as e:
|
|
900
|
-
printd(f"step() failed\
|
|
851
|
+
printd(f"step() failed\nmessages = {messages}\nerror = {e}")
|
|
901
852
|
|
|
902
853
|
# If we got a context alert, try trimming the messages length, then try again
|
|
903
854
|
if is_context_overflow_error(e):
|
|
@@ -906,14 +857,14 @@ class Agent(BaseAgent):
|
|
|
906
857
|
|
|
907
858
|
# Try step again
|
|
908
859
|
return self.step(
|
|
909
|
-
|
|
860
|
+
messages=messages,
|
|
910
861
|
first_message=first_message,
|
|
911
862
|
first_message_retry_limit=first_message_retry_limit,
|
|
912
863
|
skip_verify=skip_verify,
|
|
913
864
|
return_dicts=return_dicts,
|
|
914
|
-
recreate_message_timestamp=recreate_message_timestamp,
|
|
865
|
+
# recreate_message_timestamp=recreate_message_timestamp,
|
|
915
866
|
stream=stream,
|
|
916
|
-
timestamp=timestamp,
|
|
867
|
+
# timestamp=timestamp,
|
|
917
868
|
inner_thoughts_in_kwargs_option=inner_thoughts_in_kwargs_option,
|
|
918
869
|
ms=ms,
|
|
919
870
|
)
|
|
@@ -922,6 +873,40 @@ class Agent(BaseAgent):
|
|
|
922
873
|
printd(f"step() failed with an unrecognized exception: '{str(e)}'")
|
|
923
874
|
raise e
|
|
924
875
|
|
|
876
|
+
def step_user_message(self, user_message_str: str, **kwargs) -> AgentStepResponse:
|
|
877
|
+
"""Takes a basic user message string, turns it into a stringified JSON with extra metadata, then sends it to the agent
|
|
878
|
+
|
|
879
|
+
Example:
|
|
880
|
+
-> user_message_str = 'hi'
|
|
881
|
+
-> {'message': 'hi', 'type': 'user_message', ...}
|
|
882
|
+
-> json.dumps(...)
|
|
883
|
+
-> agent.step(messages=[Message(role='user', text=...)])
|
|
884
|
+
"""
|
|
885
|
+
# Wrap with metadata, dumps to JSON
|
|
886
|
+
assert user_message_str and isinstance(
|
|
887
|
+
user_message_str, str
|
|
888
|
+
), f"user_message_str should be a non-empty string, got {type(user_message_str)}"
|
|
889
|
+
user_message_json_str = package_user_message(user_message_str)
|
|
890
|
+
|
|
891
|
+
# Validate JSON via save/load
|
|
892
|
+
user_message = validate_json(user_message_json_str)
|
|
893
|
+
cleaned_user_message_text, name = strip_name_field_from_user_message(user_message)
|
|
894
|
+
|
|
895
|
+
# Turn into a dict
|
|
896
|
+
openai_message_dict = {"role": "user", "content": cleaned_user_message_text, "name": name}
|
|
897
|
+
|
|
898
|
+
# Create the associated Message object (in the database)
|
|
899
|
+
assert self.agent_state.user_id is not None, "User ID is not set"
|
|
900
|
+
user_message = Message.dict_to_message(
|
|
901
|
+
agent_id=self.agent_state.id,
|
|
902
|
+
user_id=self.agent_state.user_id,
|
|
903
|
+
model=self.model,
|
|
904
|
+
openai_message_dict=openai_message_dict,
|
|
905
|
+
# created_at=timestamp,
|
|
906
|
+
)
|
|
907
|
+
|
|
908
|
+
return self.step(messages=[user_message], **kwargs)
|
|
909
|
+
|
|
925
910
|
def summarize_messages_inplace(self, cutoff=None, preserve_last_N_messages=True, disallow_tool_as_first=True):
|
|
926
911
|
assert self.messages[0]["role"] == "system", f"self.messages[0] should be system (instead got {self.messages[0]})"
|
|
927
912
|
|
|
@@ -1340,7 +1325,8 @@ class Agent(BaseAgent):
|
|
|
1340
1325
|
|
|
1341
1326
|
self.pop_until_user()
|
|
1342
1327
|
user_message = self.pop_message(count=1)[0]
|
|
1343
|
-
|
|
1328
|
+
assert user_message.text is not None, "User message text is None"
|
|
1329
|
+
step_response = self.step_user_message(user_message_str=user_message.text, return_dicts=False)
|
|
1344
1330
|
messages = step_response.messages
|
|
1345
1331
|
|
|
1346
1332
|
assert messages is not None
|
|
@@ -85,9 +85,7 @@ def get_chat_completion(
|
|
|
85
85
|
elif wrapper is None:
|
|
86
86
|
# Warn the user that we're using the fallback
|
|
87
87
|
if not has_shown_warning:
|
|
88
|
-
print(
|
|
89
|
-
f"{CLI_WARNING_PREFIX}no wrapper specified for local LLM, using the default wrapper (you can remove this warning by specifying the wrapper with --model-wrapper)"
|
|
90
|
-
)
|
|
88
|
+
print(f"{CLI_WARNING_PREFIX}no prompt formatter specified for local LLM, using the default formatter")
|
|
91
89
|
has_shown_warning = True
|
|
92
90
|
|
|
93
91
|
llm_wrapper = DEFAULT_WRAPPER()
|
letta/main.py
CHANGED
|
@@ -356,19 +356,29 @@ def run_agent_loop(
|
|
|
356
356
|
else:
|
|
357
357
|
# If message did not begin with command prefix, pass inputs to Letta
|
|
358
358
|
# Handle user message and append to messages
|
|
359
|
-
user_message =
|
|
359
|
+
user_message = str(user_input)
|
|
360
360
|
|
|
361
361
|
skip_next_user_input = False
|
|
362
362
|
|
|
363
363
|
def process_agent_step(user_message, no_verify):
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
364
|
+
if user_message is None:
|
|
365
|
+
step_response = letta_agent.step(
|
|
366
|
+
messages=[],
|
|
367
|
+
first_message=False,
|
|
368
|
+
skip_verify=no_verify,
|
|
369
|
+
stream=stream,
|
|
370
|
+
inner_thoughts_in_kwargs_option=inner_thoughts_in_kwargs,
|
|
371
|
+
ms=ms,
|
|
372
|
+
)
|
|
373
|
+
else:
|
|
374
|
+
step_response = letta_agent.step_user_message(
|
|
375
|
+
user_message_str=user_message,
|
|
376
|
+
first_message=False,
|
|
377
|
+
skip_verify=no_verify,
|
|
378
|
+
stream=stream,
|
|
379
|
+
inner_thoughts_in_kwargs_option=inner_thoughts_in_kwargs,
|
|
380
|
+
ms=ms,
|
|
381
|
+
)
|
|
372
382
|
new_messages = step_response.messages
|
|
373
383
|
heartbeat_request = step_response.heartbeat_request
|
|
374
384
|
function_failed = step_response.function_failed
|
letta/providers.py
CHANGED
|
@@ -140,9 +140,17 @@ class AnthropicProvider(Provider):
|
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
class OllamaProvider(OpenAIProvider):
|
|
143
|
+
"""Ollama provider that uses the native /api/generate endpoint
|
|
144
|
+
|
|
145
|
+
See: https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion
|
|
146
|
+
"""
|
|
147
|
+
|
|
143
148
|
name: str = "ollama"
|
|
144
149
|
base_url: str = Field(..., description="Base URL for the Ollama API.")
|
|
145
150
|
api_key: Optional[str] = Field(None, description="API key for the Ollama API (default: `None`).")
|
|
151
|
+
default_prompt_formatter: str = Field(
|
|
152
|
+
..., description="Default prompt formatter (aka model wrapper) to use on a /completions style API."
|
|
153
|
+
)
|
|
146
154
|
|
|
147
155
|
def list_llm_models(self) -> List[LLMConfig]:
|
|
148
156
|
# https://github.com/ollama/ollama/blob/main/docs/api.md#list-local-models
|
|
@@ -156,11 +164,15 @@ class OllamaProvider(OpenAIProvider):
|
|
|
156
164
|
configs = []
|
|
157
165
|
for model in response_json["models"]:
|
|
158
166
|
context_window = self.get_model_context_window(model["name"])
|
|
167
|
+
if context_window is None:
|
|
168
|
+
print(f"Ollama model {model['name']} has no context window")
|
|
169
|
+
continue
|
|
159
170
|
configs.append(
|
|
160
171
|
LLMConfig(
|
|
161
172
|
model=model["name"],
|
|
162
173
|
model_endpoint_type="ollama",
|
|
163
174
|
model_endpoint=self.base_url,
|
|
175
|
+
model_wrapper=self.default_prompt_formatter,
|
|
164
176
|
context_window=context_window,
|
|
165
177
|
)
|
|
166
178
|
)
|
|
@@ -192,6 +204,10 @@ class OllamaProvider(OpenAIProvider):
|
|
|
192
204
|
# ]
|
|
193
205
|
# max_position_embeddings
|
|
194
206
|
# parse model cards: nous, dolphon, llama
|
|
207
|
+
if "model_info" not in response_json:
|
|
208
|
+
if "error" in response_json:
|
|
209
|
+
print(f"Ollama fetch model info error for {model_name}: {response_json['error']}")
|
|
210
|
+
return None
|
|
195
211
|
for key, value in response_json["model_info"].items():
|
|
196
212
|
if "context_length" in key:
|
|
197
213
|
return value
|
|
@@ -202,6 +218,10 @@ class OllamaProvider(OpenAIProvider):
|
|
|
202
218
|
|
|
203
219
|
response = requests.post(f"{self.base_url}/api/show", json={"name": model_name, "verbose": True})
|
|
204
220
|
response_json = response.json()
|
|
221
|
+
if "model_info" not in response_json:
|
|
222
|
+
if "error" in response_json:
|
|
223
|
+
print(f"Ollama fetch model info error for {model_name}: {response_json['error']}")
|
|
224
|
+
return None
|
|
205
225
|
for key, value in response_json["model_info"].items():
|
|
206
226
|
if "embedding_length" in key:
|
|
207
227
|
return value
|
|
@@ -220,6 +240,7 @@ class OllamaProvider(OpenAIProvider):
|
|
|
220
240
|
for model in response_json["models"]:
|
|
221
241
|
embedding_dim = self.get_model_embedding_dim(model["name"])
|
|
222
242
|
if not embedding_dim:
|
|
243
|
+
print(f"Ollama model {model['name']} has no embedding dimension")
|
|
223
244
|
continue
|
|
224
245
|
configs.append(
|
|
225
246
|
EmbeddingConfig(
|
|
@@ -420,7 +441,7 @@ class VLLMCompletionsProvider(Provider):
|
|
|
420
441
|
# NOTE: vLLM only serves one model at a time (so could configure that through env variables)
|
|
421
442
|
name: str = "vllm"
|
|
422
443
|
base_url: str = Field(..., description="Base URL for the vLLM API.")
|
|
423
|
-
default_prompt_formatter: str = Field(..., description="Default prompt formatter (aka model wrapper)to use on vLLM /completions API.")
|
|
444
|
+
default_prompt_formatter: str = Field(..., description="Default prompt formatter (aka model wrapper) to use on vLLM /completions API.")
|
|
424
445
|
|
|
425
446
|
def list_llm_models(self) -> List[LLMConfig]:
|
|
426
447
|
# not supported with vLLM
|
letta/server/server.py
CHANGED
|
@@ -200,7 +200,7 @@ class SyncServer(Server):
|
|
|
200
200
|
def __init__(
|
|
201
201
|
self,
|
|
202
202
|
chaining: bool = True,
|
|
203
|
-
max_chaining_steps: bool = None,
|
|
203
|
+
max_chaining_steps: Optional[bool] = None,
|
|
204
204
|
default_interface_factory: Callable[[], AgentInterface] = lambda: CLIInterface(),
|
|
205
205
|
# default_interface: AgentInterface = CLIInterface(),
|
|
206
206
|
# default_persistence_manager_cls: PersistenceManager = LocalStateManager,
|
|
@@ -241,13 +241,32 @@ class SyncServer(Server):
|
|
|
241
241
|
# collect providers (always has Letta as a default)
|
|
242
242
|
self._enabled_providers: List[Provider] = [LettaProvider()]
|
|
243
243
|
if model_settings.openai_api_key:
|
|
244
|
-
self._enabled_providers.append(
|
|
244
|
+
self._enabled_providers.append(
|
|
245
|
+
OpenAIProvider(
|
|
246
|
+
api_key=model_settings.openai_api_key,
|
|
247
|
+
base_url=model_settings.openai_api_base,
|
|
248
|
+
)
|
|
249
|
+
)
|
|
245
250
|
if model_settings.anthropic_api_key:
|
|
246
|
-
self._enabled_providers.append(
|
|
251
|
+
self._enabled_providers.append(
|
|
252
|
+
AnthropicProvider(
|
|
253
|
+
api_key=model_settings.anthropic_api_key,
|
|
254
|
+
)
|
|
255
|
+
)
|
|
247
256
|
if model_settings.ollama_base_url:
|
|
248
|
-
self._enabled_providers.append(
|
|
257
|
+
self._enabled_providers.append(
|
|
258
|
+
OllamaProvider(
|
|
259
|
+
base_url=model_settings.ollama_base_url,
|
|
260
|
+
api_key=None,
|
|
261
|
+
default_prompt_formatter=model_settings.default_prompt_formatter,
|
|
262
|
+
)
|
|
263
|
+
)
|
|
249
264
|
if model_settings.gemini_api_key:
|
|
250
|
-
self._enabled_providers.append(
|
|
265
|
+
self._enabled_providers.append(
|
|
266
|
+
GoogleAIProvider(
|
|
267
|
+
api_key=model_settings.gemini_api_key,
|
|
268
|
+
)
|
|
269
|
+
)
|
|
251
270
|
if model_settings.azure_api_key and model_settings.azure_base_url:
|
|
252
271
|
assert model_settings.azure_api_version, "AZURE_API_VERSION is required"
|
|
253
272
|
self._enabled_providers.append(
|
|
@@ -268,7 +287,11 @@ class SyncServer(Server):
|
|
|
268
287
|
# NOTE: to use the /chat/completions endpoint, you need to specify extra flags on vLLM startup
|
|
269
288
|
# see: https://docs.vllm.ai/en/latest/getting_started/examples/openai_chat_completion_client_with_tools.html
|
|
270
289
|
# e.g. "... --enable-auto-tool-choice --tool-call-parser hermes"
|
|
271
|
-
self._enabled_providers.append(
|
|
290
|
+
self._enabled_providers.append(
|
|
291
|
+
VLLMChatCompletionsProvider(
|
|
292
|
+
base_url=model_settings.vllm_api_base,
|
|
293
|
+
)
|
|
294
|
+
)
|
|
272
295
|
|
|
273
296
|
def save_agents(self):
|
|
274
297
|
"""Saves all the agents that are in the in-memory object store"""
|
|
@@ -360,9 +383,22 @@ class SyncServer(Server):
|
|
|
360
383
|
letta_agent = self._load_agent(user_id=user_id, agent_id=agent_id)
|
|
361
384
|
return letta_agent
|
|
362
385
|
|
|
363
|
-
def _step(
|
|
386
|
+
def _step(
|
|
387
|
+
self,
|
|
388
|
+
user_id: str,
|
|
389
|
+
agent_id: str,
|
|
390
|
+
input_messages: Union[Message, List[Message]],
|
|
391
|
+
# timestamp: Optional[datetime],
|
|
392
|
+
) -> LettaUsageStatistics:
|
|
364
393
|
"""Send the input message through the agent"""
|
|
365
|
-
|
|
394
|
+
|
|
395
|
+
# Input validation
|
|
396
|
+
if isinstance(input_messages, Message):
|
|
397
|
+
input_messages = [input_messages]
|
|
398
|
+
if not all(isinstance(m, Message) for m in input_messages):
|
|
399
|
+
raise ValueError(f"messages should be a Message or a list of Message, got {type(input_messages)}")
|
|
400
|
+
|
|
401
|
+
logger.debug(f"Got input messages: {input_messages}")
|
|
366
402
|
try:
|
|
367
403
|
|
|
368
404
|
# Get the agent object (loaded in memory)
|
|
@@ -375,18 +411,18 @@ class SyncServer(Server):
|
|
|
375
411
|
|
|
376
412
|
logger.debug(f"Starting agent step")
|
|
377
413
|
no_verify = True
|
|
378
|
-
next_input_message =
|
|
414
|
+
next_input_message = input_messages
|
|
379
415
|
counter = 0
|
|
380
416
|
total_usage = UsageStatistics()
|
|
381
417
|
step_count = 0
|
|
382
418
|
while True:
|
|
383
419
|
step_response = letta_agent.step(
|
|
384
|
-
next_input_message,
|
|
420
|
+
messages=next_input_message,
|
|
385
421
|
first_message=False,
|
|
386
422
|
skip_verify=no_verify,
|
|
387
423
|
return_dicts=False,
|
|
388
424
|
stream=token_streaming,
|
|
389
|
-
timestamp=timestamp,
|
|
425
|
+
# timestamp=timestamp,
|
|
390
426
|
ms=self.ms,
|
|
391
427
|
)
|
|
392
428
|
step_response.messages
|
|
@@ -413,13 +449,40 @@ class SyncServer(Server):
|
|
|
413
449
|
break
|
|
414
450
|
# Chain handlers
|
|
415
451
|
elif token_warning:
|
|
416
|
-
|
|
452
|
+
assert letta_agent.agent_state.user_id is not None
|
|
453
|
+
next_input_message = Message.dict_to_message(
|
|
454
|
+
agent_id=letta_agent.agent_state.id,
|
|
455
|
+
user_id=letta_agent.agent_state.user_id,
|
|
456
|
+
model=letta_agent.model,
|
|
457
|
+
openai_message_dict={
|
|
458
|
+
"role": "user", # TODO: change to system?
|
|
459
|
+
"content": system.get_token_limit_warning(),
|
|
460
|
+
},
|
|
461
|
+
)
|
|
417
462
|
continue # always chain
|
|
418
463
|
elif function_failed:
|
|
419
|
-
|
|
464
|
+
assert letta_agent.agent_state.user_id is not None
|
|
465
|
+
next_input_message = Message.dict_to_message(
|
|
466
|
+
agent_id=letta_agent.agent_state.id,
|
|
467
|
+
user_id=letta_agent.agent_state.user_id,
|
|
468
|
+
model=letta_agent.model,
|
|
469
|
+
openai_message_dict={
|
|
470
|
+
"role": "user", # TODO: change to system?
|
|
471
|
+
"content": system.get_heartbeat(constants.FUNC_FAILED_HEARTBEAT_MESSAGE),
|
|
472
|
+
},
|
|
473
|
+
)
|
|
420
474
|
continue # always chain
|
|
421
475
|
elif heartbeat_request:
|
|
422
|
-
|
|
476
|
+
assert letta_agent.agent_state.user_id is not None
|
|
477
|
+
next_input_message = Message.dict_to_message(
|
|
478
|
+
agent_id=letta_agent.agent_state.id,
|
|
479
|
+
user_id=letta_agent.agent_state.user_id,
|
|
480
|
+
model=letta_agent.model,
|
|
481
|
+
openai_message_dict={
|
|
482
|
+
"role": "user", # TODO: change to system?
|
|
483
|
+
"content": system.get_heartbeat(constants.REQ_HEARTBEAT_MESSAGE),
|
|
484
|
+
},
|
|
485
|
+
)
|
|
423
486
|
continue # always chain
|
|
424
487
|
# Letta no-op / yield
|
|
425
488
|
else:
|
|
@@ -598,7 +661,7 @@ class SyncServer(Server):
|
|
|
598
661
|
)
|
|
599
662
|
|
|
600
663
|
# Run the agent state forward
|
|
601
|
-
usage = self._step(user_id=user_id, agent_id=agent_id,
|
|
664
|
+
usage = self._step(user_id=user_id, agent_id=agent_id, input_messages=message)
|
|
602
665
|
return usage
|
|
603
666
|
|
|
604
667
|
def system_message(
|
|
@@ -646,7 +709,7 @@ class SyncServer(Server):
|
|
|
646
709
|
|
|
647
710
|
if isinstance(message, Message):
|
|
648
711
|
# Can't have a null text field
|
|
649
|
-
if
|
|
712
|
+
if message.text is None or len(message.text) == 0:
|
|
650
713
|
raise ValueError(f"Invalid input: '{message.text}'")
|
|
651
714
|
# If the input begins with a command prefix, reject
|
|
652
715
|
elif message.text.startswith("/"):
|
|
@@ -660,7 +723,7 @@ class SyncServer(Server):
|
|
|
660
723
|
message.created_at = timestamp
|
|
661
724
|
|
|
662
725
|
# Run the agent state forward
|
|
663
|
-
return self._step(user_id=user_id, agent_id=agent_id,
|
|
726
|
+
return self._step(user_id=user_id, agent_id=agent_id, input_messages=message)
|
|
664
727
|
|
|
665
728
|
# @LockingServer.agent_lock_decorator
|
|
666
729
|
def run_command(self, user_id: str, agent_id: str, command: str) -> LettaUsageStatistics:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
letta/__init__.py,sha256=btKRPdyhkpIyHlCPRLwwz-SCSVcEGNBeheYA-XNesiI,996
|
|
2
2
|
letta/__main__.py,sha256=6Hs2PV7EYc5Tid4g4OtcLXhqVHiNYTGzSBdoOnW2HXA,29
|
|
3
|
-
letta/agent.py,sha256=
|
|
3
|
+
letta/agent.py,sha256=S30yzTZjsbe3mn9Zn9eUBquL-JehUTZIStRyp7LL04s,65548
|
|
4
4
|
letta/agent_store/chroma.py,sha256=upR5zGnGs6I6btulEYbiZdGG87BgKjxUJOQZ4Y-RQ_M,12492
|
|
5
5
|
letta/agent_store/db.py,sha256=TAQ1rcqS8zuC1hT_BaiXn6tSz5aKHAb-YQxr4QLKgz4,22724
|
|
6
6
|
letta/agent_store/lancedb.py,sha256=8RWmqVjowm5g0cc6DNRcb6f1FHGEqFnccnuekhWY39U,5101
|
|
@@ -45,7 +45,7 @@ letta/llm_api/llm_api_tools.py,sha256=Z3eiYUtvZKBVBcmKI2l4qWkKM4hgvLN9Y1aSxXc7y-
|
|
|
45
45
|
letta/llm_api/openai.py,sha256=EXpktSI_TYjsCDEXBxdNXsY5uE9Rzb7BPF1F6cz8bkg,21689
|
|
46
46
|
letta/local_llm/README.md,sha256=hFJyw5B0TU2jrh9nb0zGZMgdH-Ei1dSRfhvPQG_NSoU,168
|
|
47
47
|
letta/local_llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
|
-
letta/local_llm/chat_completion_proxy.py,sha256=
|
|
48
|
+
letta/local_llm/chat_completion_proxy.py,sha256=SiohxsjGTku4vOryOZx7I0t0xoO_sUuhXgoe62fKq3c,12995
|
|
49
49
|
letta/local_llm/constants.py,sha256=GIu0184EIiOLEqGeupLUYQvkgT_imIjLg3T-KM9TcFM,1125
|
|
50
50
|
letta/local_llm/function_parser.py,sha256=BlNsGo1VzyfY5KdF_RwjRQNOWIsaudo7o37u1W5eg0s,2626
|
|
51
51
|
letta/local_llm/grammars/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -81,7 +81,7 @@ letta/local_llm/webui/legacy_api.py,sha256=k3H3y4qp2Fs-XmP24iSIEyvq6wjWFWBzklY3-
|
|
|
81
81
|
letta/local_llm/webui/legacy_settings.py,sha256=BLmd3TSx5StnY3ibjwaxYATPt_Lvq-o1rlcc_-Q1JcU,538
|
|
82
82
|
letta/local_llm/webui/settings.py,sha256=gmLHfiOl1u4JmlAZU2d2O8YKF9lafdakyjwR_ftVPh8,552
|
|
83
83
|
letta/log.py,sha256=QHquDnL7oUAvdKlAwUlCK9zXKDMUjrU9WA0bxnMsP0Y,2101
|
|
84
|
-
letta/main.py,sha256=
|
|
84
|
+
letta/main.py,sha256=4zO3UDos93HXPJQtz5tO77KAlSgx5xZIgEigpEtars4,18920
|
|
85
85
|
letta/memory.py,sha256=6q1x3-PY-PeXzAt6hvP-UF1ajvroPZ7XW-5nLy-JhMo,17657
|
|
86
86
|
letta/metadata.py,sha256=50pEJ5BuNKT8dPv34-H_Id9an3ql45Ze7BKqn7DGQ6s,33256
|
|
87
87
|
letta/openai_backcompat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -107,7 +107,7 @@ letta/prompts/system/memgpt_doc.txt,sha256=AsT55NOORoH-K-p0fxklrDRZ3qHs4MIKMuR-M
|
|
|
107
107
|
letta/prompts/system/memgpt_gpt35_extralong.txt,sha256=FheNhYoIzNz6qnJKhVquZVSMj3HduC48reFaX7Pf7ig,5046
|
|
108
108
|
letta/prompts/system/memgpt_intuitive_knowledge.txt,sha256=sA7c3urYqREVnSBI81nTGImXAekqC0Fxc7RojFqud1g,2966
|
|
109
109
|
letta/prompts/system/memgpt_modified_chat.txt,sha256=HOaPVurEftD8KsuwsclDgE2afIfklMjxhuSO96q1-6I,4656
|
|
110
|
-
letta/providers.py,sha256=
|
|
110
|
+
letta/providers.py,sha256=e4jWshGMu4UQ9B0yEzcHP1bDxNHEo_mgpO5M0txuOIo,17978
|
|
111
111
|
letta/pytest.ini,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
112
112
|
letta/schemas/agent.py,sha256=ztnUqdhY9V3g0jsbTjF1ypKPC1tZx4QVFaRuLAOXNSA,6230
|
|
113
113
|
letta/schemas/api_key.py,sha256=u07yzzMn-hBAHZIIKbWY16KsgiFjSNR8lAghpMUo3_4,682
|
|
@@ -167,7 +167,7 @@ letta/server/rest_api/routers/v1/tools.py,sha256=MEhxu-zMS2ff_wwcRpMuQyWA71w_3BJ
|
|
|
167
167
|
letta/server/rest_api/routers/v1/users.py,sha256=Y2rDvHOG1B5FLSOjutY3R22vt48IngbZ-9h8CohG5rc,3378
|
|
168
168
|
letta/server/rest_api/static_files.py,sha256=NG8sN4Z5EJ8JVQdj19tkFa9iQ1kBPTab9f_CUxd_u4Q,3143
|
|
169
169
|
letta/server/rest_api/utils.py,sha256=Fc2ZGKzLaBa2sEtSTVjJ8D5M0xIwsWC0CVAOIJaD3rY,2176
|
|
170
|
-
letta/server/server.py,sha256=
|
|
170
|
+
letta/server/server.py,sha256=Fs9cJLSDuh1qbyB81QD9oOUmHqChWzOkysjZvr-ghxk,84438
|
|
171
171
|
letta/server/startup.sh,sha256=jeGV7B_PS0hS-tT6o6GpACrUbV9WV1NI2L9aLoUDDtc,311
|
|
172
172
|
letta/server/static_files/assets/index-3ab03d5b.css,sha256=OrA9W4iKJ5h2Wlr7GwdAT4wow0CM8hVit1yOxEL49Qw,54295
|
|
173
173
|
letta/server/static_files/assets/index-9a9c449b.js,sha256=qoWUq6_kuLhE9NFkNeCBptgq-oERW46r0tB3JlWe_qc,1818951
|
|
@@ -184,8 +184,8 @@ letta/settings.py,sha256=6VWC3vtTa8vqj6dqos4p_xHTMJNJS_8LRGJmqvaU1-o,3219
|
|
|
184
184
|
letta/streaming_interface.py,sha256=_FPUWy58j50evHcpXyd7zB1wWqeCc71NCFeWh_TBvnw,15736
|
|
185
185
|
letta/system.py,sha256=buKYPqG5n2x41hVmWpu6JUpyd7vTWED9Km2_M7dLrvk,6960
|
|
186
186
|
letta/utils.py,sha256=neUs7mxNfndzRL5XUxerr8Lic6w7qnyyvf8FBwMnyWw,30852
|
|
187
|
-
letta_nightly-0.4.1.
|
|
188
|
-
letta_nightly-0.4.1.
|
|
189
|
-
letta_nightly-0.4.1.
|
|
190
|
-
letta_nightly-0.4.1.
|
|
191
|
-
letta_nightly-0.4.1.
|
|
187
|
+
letta_nightly-0.4.1.dev20241014104152.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
|
|
188
|
+
letta_nightly-0.4.1.dev20241014104152.dist-info/METADATA,sha256=55FccQj8oSaEHu0ve8g1JQU96_WBhTW07R0IVg2XOcg,6008
|
|
189
|
+
letta_nightly-0.4.1.dev20241014104152.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
190
|
+
letta_nightly-0.4.1.dev20241014104152.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
|
|
191
|
+
letta_nightly-0.4.1.dev20241014104152.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|