letta-nightly 0.8.7.dev20250629104239__py3-none-any.whl → 0.8.8.dev20250630104345__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 CHANGED
@@ -1,6 +1,6 @@
1
1
  import os
2
2
 
3
- __version__ = "0.8.7"
3
+ __version__ = "0.8.8"
4
4
 
5
5
 
6
6
  if os.environ.get("LETTA_VERSION"):
letta/agents/helpers.py CHANGED
@@ -210,17 +210,21 @@ def generate_step_id():
210
210
  return f"step-{uuid.uuid4()}"
211
211
 
212
212
 
213
- def _safe_load_dict(raw: str) -> dict:
213
+ def _safe_load_tool_call_str(tool_call_args_str: str) -> dict:
214
214
  """Lenient JSON → dict with fallback to eval on assertion failure."""
215
- if "}{" in raw: # strip accidental parallel calls
216
- raw = raw.split("}{", 1)[0] + "}"
215
+ # Temp hack to gracefully handle parallel tool calling attempt, only take first one
216
+ if "}{" in tool_call_args_str:
217
+ tool_call_args_str = tool_call_args_str.split("}{", 1)[0] + "}"
218
+
217
219
  try:
218
- data = json.loads(raw)
219
- if not isinstance(data, dict):
220
- raise AssertionError
221
- return data
222
- except (json.JSONDecodeError, AssertionError):
223
- return json.loads(raw) if raw else {}
220
+ tool_args = json.loads(tool_call_args_str)
221
+ if not isinstance(tool_args, dict):
222
+ # Load it again - this is due to sometimes Anthropic returning weird json @caren
223
+ tool_args = json.loads(tool_args)
224
+ except json.JSONDecodeError:
225
+ tool_args = {}
226
+
227
+ return tool_args
224
228
 
225
229
 
226
230
  def _pop_heartbeat(tool_args: dict) -> bool:
@@ -15,7 +15,7 @@ from letta.agents.helpers import (
15
15
  _create_letta_response,
16
16
  _pop_heartbeat,
17
17
  _prepare_in_context_messages_no_persist_async,
18
- _safe_load_dict,
18
+ _safe_load_tool_call_str,
19
19
  generate_step_id,
20
20
  )
21
21
  from letta.constants import DEFAULT_MAX_STEPS, NON_USER_MSG_PREFIX
@@ -944,7 +944,7 @@ class LettaAgent(BaseAgent):
944
944
  # 1. Parse and validate the tool-call envelope
945
945
  tool_call_name: str = tool_call.function.name
946
946
  tool_call_id: str = tool_call.id or f"call_{uuid.uuid4().hex[:8]}"
947
- tool_args = _safe_load_dict(tool_call.function.arguments)
947
+ tool_args = _safe_load_tool_call_str(tool_call.function.arguments)
948
948
  request_heartbeat: bool = _pop_heartbeat(tool_args)
949
949
  tool_args.pop(INNER_THOUGHTS_KWARG, None)
950
950
 
@@ -993,6 +993,7 @@ class LettaAgent(BaseAgent):
993
993
 
994
994
  # 4. Decide whether to keep stepping (<<< focal section simplified)
995
995
  continue_stepping, heartbeat_reason, stop_reason = self._decide_continuation(
996
+ agent_state=agent_state,
996
997
  request_heartbeat=request_heartbeat,
997
998
  tool_call_name=tool_call_name,
998
999
  tool_rule_violated=tool_rule_violated,
@@ -1048,6 +1049,7 @@ class LettaAgent(BaseAgent):
1048
1049
 
1049
1050
  def _decide_continuation(
1050
1051
  self,
1052
+ agent_state: AgentState,
1051
1053
  request_heartbeat: bool,
1052
1054
  tool_call_name: str,
1053
1055
  tool_rule_violated: bool,
@@ -1083,10 +1085,12 @@ class LettaAgent(BaseAgent):
1083
1085
  continue_stepping = False
1084
1086
  stop_reason = LettaStopReason(stop_reason=StopReasonType.max_steps.value)
1085
1087
  else:
1086
- uncalled = tool_rules_solver.get_uncalled_required_tools()
1088
+ uncalled = tool_rules_solver.get_uncalled_required_tools(available_tools=set([t.name for t in agent_state.tools]))
1087
1089
  if not continue_stepping and uncalled:
1088
1090
  continue_stepping = True
1089
- heartbeat_reason = f"{NON_USER_MSG_PREFIX}Missing required tools: " f"{', '.join(uncalled)}"
1091
+ heartbeat_reason = (
1092
+ f"{NON_USER_MSG_PREFIX}Continuing, user expects these tools: [" f"{', '.join(uncalled)}] to be called still."
1093
+ )
1090
1094
 
1091
1095
  stop_reason = None # reset – we’re still going
1092
1096
 
@@ -151,11 +151,11 @@ class ToolRulesSolver(BaseModel):
151
151
  """Check if the tool is defined as a continue tool in the tool rules."""
152
152
  return any(rule.tool_name == tool_name for rule in self.continue_tool_rules)
153
153
 
154
- def has_required_tools_been_called(self) -> bool:
154
+ def has_required_tools_been_called(self, available_tools: Set[str]) -> bool:
155
155
  """Check if all required-before-exit tools have been called."""
156
- return len(self.get_uncalled_required_tools()) == 0
156
+ return len(self.get_uncalled_required_tools(available_tools=available_tools)) == 0
157
157
 
158
- def get_uncalled_required_tools(self) -> List[str]:
158
+ def get_uncalled_required_tools(self, available_tools: Set[str]) -> List[str]:
159
159
  """Get the list of required-before-exit tools that have not been called yet."""
160
160
  if not self.required_before_exit_tool_rules:
161
161
  return [] # No required tools means no uncalled tools
@@ -163,7 +163,8 @@ class ToolRulesSolver(BaseModel):
163
163
  required_tool_names = {rule.tool_name for rule in self.required_before_exit_tool_rules}
164
164
  called_tool_names = set(self.tool_call_history)
165
165
 
166
- return list(required_tool_names - called_tool_names)
166
+ # Get required tools that are uncalled AND available
167
+ return list((required_tool_names & available_tools) - called_tool_names)
167
168
 
168
169
  def get_ending_tool_names(self) -> List[str]:
169
170
  """Get the names of tools that are required before exit."""
@@ -243,6 +243,7 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
243
243
  join_conditions=join_conditions,
244
244
  identifier_keys=identifier_keys,
245
245
  identity_id=identity_id,
246
+ has_feedback=has_feedback,
246
247
  **kwargs,
247
248
  )
248
249
  if query_options:
@@ -779,6 +779,7 @@ class AgentManager:
779
779
  "response_format": agent_update.response_format,
780
780
  "last_run_completion": agent_update.last_run_completion,
781
781
  "last_run_duration_ms": agent_update.last_run_duration_ms,
782
+ "timezone": agent_update.timezone,
782
783
  }
783
784
  for col, val in scalar_updates.items():
784
785
  if val is not None:
@@ -2051,7 +2052,11 @@ class AgentManager:
2051
2052
  except NoResultFound:
2052
2053
  # Agent might not exist anymore, skip
2053
2054
  continue
2054
- session.commit()
2055
+
2056
+ # TODO: @andy/caren
2057
+ # TODO: Ideally we do two no commits on the update_async calls, and then commit here - but that errors for some reason?
2058
+ # TODO: I have too many things rn so lets look at this later
2059
+ # await session.commit()
2055
2060
 
2056
2061
  return await agent.to_pydantic_async()
2057
2062
 
@@ -49,6 +49,7 @@ class FileTypeRegistry:
49
49
  self.register(".markdown", "text/markdown", True, "Markdown document", ChunkingStrategy.DOCUMENTATION)
50
50
  self.register(".json", "application/json", True, "JSON data file", ChunkingStrategy.STRUCTURED_DATA)
51
51
  self.register(".jsonl", "application/jsonl", True, "JSON Lines file", ChunkingStrategy.STRUCTURED_DATA)
52
+ self.register(".csv", "text/csv", True, "CSV data file", ChunkingStrategy.STRUCTURED_DATA)
52
53
 
53
54
  # Programming languages
54
55
  self.register(".py", "text/x-python", True, "Python source code", ChunkingStrategy.CODE)
@@ -137,6 +138,7 @@ class FileTypeRegistry:
137
138
  mimetypes.add_type("text/x-markdown", ".md")
138
139
  mimetypes.add_type("application/x-jsonlines", ".jsonl")
139
140
  mimetypes.add_type("text/xml", ".xml")
141
+ mimetypes.add_type("text/csv", ".csv")
140
142
 
141
143
  def get_allowed_media_types(self) -> Set[str]:
142
144
  """
letta/utils.py CHANGED
@@ -531,6 +531,10 @@ def enforce_types(func):
531
531
  elif origin is list and isinstance(value, list): # Handle List[T]
532
532
  element_type = args[0] if args else None
533
533
  return all(isinstance(v, element_type) for v in value) if element_type else True
534
+ elif origin is not None and (
535
+ str(origin).endswith("Literal") or getattr(origin, "_name", None) == "Literal"
536
+ ): # Handle Literal types
537
+ return value in args
534
538
  elif origin: # Handle other generics like Dict, Tuple, etc.
535
539
  return isinstance(value, origin)
536
540
  else: # Handle non-generic types
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: letta-nightly
3
- Version: 0.8.7.dev20250629104239
3
+ Version: 0.8.8.dev20250630104345
4
4
  Summary: Create LLM agents with long-term memory and custom tools
5
5
  License: Apache License
6
6
  Author: Letta Team
@@ -1,12 +1,12 @@
1
- letta/__init__.py,sha256=lOUklJSTcBdSfR5NdRUgUPfzmqrkcgpB7cHXQlchEdU,1043
1
+ letta/__init__.py,sha256=qFQJGPrcmwxPDtXS2lrVBj_uI4R-ANeKxnygFadRNWg,1043
2
2
  letta/agent.py,sha256=PLTHwDvgl4Nffi_NBm3Jn40H39t7Z6_kZWJ8sswNlpk,89097
3
3
  letta/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  letta/agents/base_agent.py,sha256=ymn0Uq9VcImoHmmnP0DyXQ-D3trmpcYVCdi7S9p0fKs,6571
5
5
  letta/agents/ephemeral_agent.py,sha256=el-SUF_16vv_7OouIR-6z0pAE9Yc0PLibygvfCKwqfo,2736
6
6
  letta/agents/ephemeral_summary_agent.py,sha256=MgJZxmlMU8ZKOKfqMAH7t2WMlf7zW0ZliVuCxxeHehk,4101
7
7
  letta/agents/exceptions.py,sha256=BQY4D4w32OYHM63CM19ko7dPwZiAzUs3NbKvzmCTcJg,318
8
- letta/agents/helpers.py,sha256=_lfaIzIc2xtUdnM0NmMvNwxljrlr3Y7VBHkmKyjwB_E,9810
9
- letta/agents/letta_agent.py,sha256=iOJvoxrlBjwYhjRSiQHBfpmc8MDoMyqwaCzRVk6kKfQ,53444
8
+ letta/agents/helpers.py,sha256=reSrQCEgIz8wE2FKIr-Gm6jsJeihS607BPqFVs_jaK0,10025
9
+ letta/agents/letta_agent.py,sha256=5DtcSAfY3zprbk27TA1DlscttIwCgZoN8FrnKwMKllI,53664
10
10
  letta/agents/letta_agent_batch.py,sha256=cl9_nZYflIZWR23D_x_fUpmMHYITDWu0FUfPW1ivDuw,28031
11
11
  letta/agents/prompts/summary_system_prompt.txt,sha256=ftc-aEhfJYN6FlQF4I-I5me-BAh_T2nsTwitPZpZisE,2313
12
12
  letta/agents/voice_agent.py,sha256=FE9F1PN4nCUnNQhgoJssAFiJKZz1DiThyRDE3Xcf14Y,23420
@@ -62,7 +62,7 @@ letta/helpers/json_helpers.py,sha256=PWZ5HhSqGXO4e563dM_8M72q7ScirjXQ4Rv1ckohaV8
62
62
  letta/helpers/message_helper.py,sha256=Xzf_VCMAXT0Ys8LVUh1ySVtgJwabSQYksOdPr7P4EJU,3549
63
63
  letta/helpers/singleton.py,sha256=Y4dG_ZBCcrogvl9iZ69bSLq-QltrdP8wHqKkhef8OBI,370
64
64
  letta/helpers/tool_execution_helper.py,sha256=BgBgVLZzbc-JTdOGwyU9miV_-zM3A30jkMpwH1otxaU,7599
65
- letta/helpers/tool_rule_solver.py,sha256=GWo4uzwWS2ZUYdbjG-CYx99q095N3G3eedgt2VKWdhQ,11454
65
+ letta/helpers/tool_rule_solver.py,sha256=avRMQzqxE2r6gRvw7oTImYmkSvuoMHlADPND0__feBw,11620
66
66
  letta/humans/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
67
  letta/humans/examples/basic.txt,sha256=Lcp8YESTWvOJgO4Yf_yyQmgo5bKakeB1nIVrwEGG6PA,17
68
68
  letta/humans/examples/cs_phd.txt,sha256=9C9ZAV_VuG7GB31ksy3-_NAyk8rjE6YtVOkhp08k1xw,297
@@ -171,7 +171,7 @@ letta/orm/provider_trace.py,sha256=CJMGz-rLqagJ-yXh9SJRbiGr5nAYdxY524hmiTgDFx4,1
171
171
  letta/orm/sandbox_config.py,sha256=zOCvORexDBt16mc6A3U65EI6_2Xe3Roh7k2asLeFMps,4242
172
172
  letta/orm/source.py,sha256=rtehzez80rRrJigXeRBgTlfTZEUy6cVqDizWEN2tvuY,2224
173
173
  letta/orm/sources_agents.py,sha256=Ik_PokCBrXRd9wXWomeNeb8EtLUwjb9VMZ8LWXqpK5A,473
174
- letta/orm/sqlalchemy_base.py,sha256=L6dX5_InnYWB9HRhYAY2j_yA9Oye5uxmmSIq9PCuEDo,44399
174
+ letta/orm/sqlalchemy_base.py,sha256=N90RIye2ubLRklJAPEVrLkh7sV30DKLcFmAKHrCgXcY,44438
175
175
  letta/orm/sqlite_functions.py,sha256=JCScKiRlYCKxy9hChQ8wsk4GMKknZE24MunnG3fM1Gw,4255
176
176
  letta/orm/step.py,sha256=SLsLY1g4nuUeI47q9rlXPBCSVUNX3lxYAYAIqxy-YK4,3517
177
177
  letta/orm/tool.py,sha256=oTDbvSNNW_jHjYbJqqsLLuXf9uFRTZTZh33TXAcZ898,2839
@@ -333,7 +333,7 @@ letta/server/ws_api/interface.py,sha256=TWl9vkcMCnLsUtgsuENZ-ku2oMDA-OUTzLh_yNRo
333
333
  letta/server/ws_api/protocol.py,sha256=5mDgpfNZn_kNwHnpt5Dsuw8gdNH298sgxTGed3etzYg,1836
334
334
  letta/server/ws_api/server.py,sha256=cBSzf-V4zT1bL_0i54OTI3cMXhTIIxqjSRF8pYjk7fg,5835
335
335
  letta/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
336
- letta/services/agent_manager.py,sha256=BAj7wu74BXp6U7keQ2YPmIgavCVN9MCYcf_9J0Fscl8,121041
336
+ letta/services/agent_manager.py,sha256=J7eOEFoJuaCDo9kG3l7J7FKGPtzdxRDm9eqNxGN344k,121338
337
337
  letta/services/block_manager.py,sha256=YwDGdy6f6MNXVXVOxIMOOP6IEWT8h-k5uQlveof0pyE,22744
338
338
  letta/services/context_window_calculator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
339
339
  letta/services/context_window_calculator/context_window_calculator.py,sha256=H0-Ello1DHV28MnzMseWrg--jarDc6YwCcgwPlWjtZk,6527
@@ -346,7 +346,7 @@ letta/services/file_processor/chunker/llama_index_chunker.py,sha256=dEBf33TifD_B
346
346
  letta/services/file_processor/embedder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
347
347
  letta/services/file_processor/embedder/openai_embedder.py,sha256=BjKsNqh_nfNIDVWkCR2noFX7E6Mr68FQtj79F2xeCpM,3545
348
348
  letta/services/file_processor/file_processor.py,sha256=xOcoQRgekcZo4JrrXMNYKSiuN4vPKxc81HuS2G3sFPs,4803
349
- letta/services/file_processor/file_types.py,sha256=AAwflpGrCmKBtZvzUR-TdOkOp5OGky6vm2ZbhRg7_WY,12982
349
+ letta/services/file_processor/file_types.py,sha256=9k3Lt_bquQjJ7T6L12fPS9IS5wldhJ2puSkH6rhfCaE,13128
350
350
  letta/services/file_processor/parser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
351
351
  letta/services/file_processor/parser/base_parser.py,sha256=WfnXP6fL-xQz4eIHEWa6-ZNEAARbF_alowqH4BAUzJo,238
352
352
  letta/services/file_processor/parser/mistral_parser.py,sha256=Hzsrm36HbKQ7CWljTZT1RgbvxE4gvSBq76Ucj80jjeQ,2322
@@ -404,9 +404,9 @@ letta/templates/sandbox_code_file.py.j2,sha256=zgzaboDZVtM15XkxILnhiKisF7DSUoI2Y
404
404
  letta/templates/sandbox_code_file_async.py.j2,sha256=hL6UWt4L16o79OPOBq1_Cw7gR5-gpaR_esbmU8bSp8w,1805
405
405
  letta/templates/template_helper.py,sha256=uHWO1PukgMoIIvgqQdPyHq3o3CQ6mcjUjTGvx9VLGkk,409
406
406
  letta/types/__init__.py,sha256=hokKjCVFGEfR7SLMrtZsRsBfsC7yTIbgKPLdGg4K1eY,147
407
- letta/utils.py,sha256=WkPJD9cs00CKgu5ezcTz5vSP76npyuBOpK7paQDQtxk,33224
408
- letta_nightly-0.8.7.dev20250629104239.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
409
- letta_nightly-0.8.7.dev20250629104239.dist-info/METADATA,sha256=7NuedgUOSW_IK2r9qay54kjQQ8oyU7S6ljjqqbziSRY,22841
410
- letta_nightly-0.8.7.dev20250629104239.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
411
- letta_nightly-0.8.7.dev20250629104239.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
412
- letta_nightly-0.8.7.dev20250629104239.dist-info/RECORD,,
407
+ letta/utils.py,sha256=tpJIzZetCfkCPI2YixMp_6tul7QgjdO6_G6Yg2_nYa4,33437
408
+ letta_nightly-0.8.8.dev20250630104345.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
409
+ letta_nightly-0.8.8.dev20250630104345.dist-info/METADATA,sha256=gPHo8DKY7FGcBfQxX-BOy0kqon3Tmdi0QRbVPPR59Lk,22841
410
+ letta_nightly-0.8.8.dev20250630104345.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
411
+ letta_nightly-0.8.8.dev20250630104345.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
412
+ letta_nightly-0.8.8.dev20250630104345.dist-info/RECORD,,