letta-nightly 0.5.4.dev20241125104219__tar.gz → 0.5.4.dev20241127104220__tar.gz

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 (227) hide show
  1. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/PKG-INFO +1 -1
  2. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/agent.py +6 -0
  3. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/cli/cli_config.py +1 -1
  4. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/client/client.py +72 -47
  5. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/errors.py +12 -0
  6. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/functions/functions.py +4 -6
  7. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/functions/schema_generator.py +6 -5
  8. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/metadata.py +6 -1
  9. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/block.py +2 -1
  10. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/blocks_agents.py +4 -1
  11. letta_nightly-0.5.4.dev20241127104220/letta/orm/errors.py +14 -0
  12. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/sqlalchemy_base.py +59 -7
  13. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/block.py +1 -1
  14. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/tool.py +25 -1
  15. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/agents.py +15 -13
  16. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/tools.py +48 -7
  17. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/server.py +10 -2
  18. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/block_manager.py +17 -1
  19. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/blocks_agents_manager.py +8 -1
  20. letta_nightly-0.5.4.dev20241127104220/letta/services/per_agent_lock_manager.py +18 -0
  21. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/tool_manager.py +5 -12
  22. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/pyproject.toml +1 -1
  23. letta_nightly-0.5.4.dev20241125104219/letta/orm/errors.py +0 -6
  24. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/LICENSE +0 -0
  25. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/README.md +0 -0
  26. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/__init__.py +0 -0
  27. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/__main__.py +0 -0
  28. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/agent_store/chroma.py +0 -0
  29. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/agent_store/db.py +0 -0
  30. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/agent_store/lancedb.py +0 -0
  31. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/agent_store/milvus.py +0 -0
  32. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/agent_store/qdrant.py +0 -0
  33. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/agent_store/storage.py +0 -0
  34. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/benchmark/benchmark.py +0 -0
  35. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/benchmark/constants.py +0 -0
  36. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/cli/cli.py +0 -0
  37. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/cli/cli_load.py +0 -0
  38. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/client/__init__.py +0 -0
  39. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/client/streaming.py +0 -0
  40. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/client/utils.py +0 -0
  41. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/config.py +0 -0
  42. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/constants.py +0 -0
  43. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/credentials.py +0 -0
  44. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/data_sources/connectors.py +0 -0
  45. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/data_sources/connectors_helper.py +0 -0
  46. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/embeddings.py +0 -0
  47. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/functions/__init__.py +0 -0
  48. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/functions/function_sets/base.py +0 -0
  49. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/functions/function_sets/extras.py +0 -0
  50. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/functions/helpers.py +0 -0
  51. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/helpers/__init__.py +0 -0
  52. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/helpers/tool_rule_solver.py +0 -0
  53. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/humans/__init__.py +0 -0
  54. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/humans/examples/basic.txt +0 -0
  55. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/humans/examples/cs_phd.txt +0 -0
  56. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/interface.py +0 -0
  57. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/llm_api/__init__.py +0 -0
  58. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/llm_api/anthropic.py +0 -0
  59. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/llm_api/azure_openai.py +0 -0
  60. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/llm_api/azure_openai_constants.py +0 -0
  61. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/llm_api/cohere.py +0 -0
  62. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/llm_api/google_ai.py +0 -0
  63. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/llm_api/helpers.py +0 -0
  64. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/llm_api/llm_api_tools.py +0 -0
  65. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/llm_api/mistral.py +0 -0
  66. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/llm_api/openai.py +0 -0
  67. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/README.md +0 -0
  68. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/__init__.py +0 -0
  69. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/chat_completion_proxy.py +0 -0
  70. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/constants.py +0 -0
  71. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/function_parser.py +0 -0
  72. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/grammars/__init__.py +0 -0
  73. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/grammars/gbnf_grammar_generator.py +0 -0
  74. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/grammars/json.gbnf +0 -0
  75. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/grammars/json_func_calls_with_inner_thoughts.gbnf +0 -0
  76. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/json_parser.py +0 -0
  77. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/koboldcpp/api.py +0 -0
  78. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/koboldcpp/settings.py +0 -0
  79. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llamacpp/api.py +0 -0
  80. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llamacpp/settings.py +0 -0
  81. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llm_chat_completion_wrappers/__init__.py +0 -0
  82. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llm_chat_completion_wrappers/airoboros.py +0 -0
  83. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llm_chat_completion_wrappers/chatml.py +0 -0
  84. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +0 -0
  85. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llm_chat_completion_wrappers/dolphin.py +0 -0
  86. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llm_chat_completion_wrappers/llama3.py +0 -0
  87. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llm_chat_completion_wrappers/simple_summary_wrapper.py +0 -0
  88. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llm_chat_completion_wrappers/wrapper_base.py +0 -0
  89. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/llm_chat_completion_wrappers/zephyr.py +0 -0
  90. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/lmstudio/api.py +0 -0
  91. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/lmstudio/settings.py +0 -0
  92. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/ollama/api.py +0 -0
  93. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/ollama/settings.py +0 -0
  94. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/settings/__init__.py +0 -0
  95. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/settings/deterministic_mirostat.py +0 -0
  96. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/settings/settings.py +0 -0
  97. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/settings/simple.py +0 -0
  98. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/utils.py +0 -0
  99. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/vllm/api.py +0 -0
  100. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/webui/api.py +0 -0
  101. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/webui/legacy_api.py +0 -0
  102. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/webui/legacy_settings.py +0 -0
  103. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/local_llm/webui/settings.py +0 -0
  104. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/log.py +0 -0
  105. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/main.py +0 -0
  106. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/memory.py +0 -0
  107. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/o1_agent.py +0 -0
  108. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/openai_backcompat/__init__.py +0 -0
  109. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/openai_backcompat/openai_object.py +0 -0
  110. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/__all__.py +0 -0
  111. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/__init__.py +0 -0
  112. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/agents_tags.py +0 -0
  113. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/base.py +0 -0
  114. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/enums.py +0 -0
  115. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/file.py +0 -0
  116. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/mixins.py +0 -0
  117. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/organization.py +0 -0
  118. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/sandbox_config.py +0 -0
  119. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/source.py +0 -0
  120. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/tool.py +0 -0
  121. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/orm/user.py +0 -0
  122. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/persistence_manager.py +0 -0
  123. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/personas/__init__.py +0 -0
  124. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/personas/examples/anna_pa.txt +0 -0
  125. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/personas/examples/google_search_persona.txt +0 -0
  126. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/personas/examples/memgpt_doc.txt +0 -0
  127. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/personas/examples/memgpt_starter.txt +0 -0
  128. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/personas/examples/o1_persona.txt +0 -0
  129. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/personas/examples/sam.txt +0 -0
  130. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/personas/examples/sam_pov.txt +0 -0
  131. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/personas/examples/sam_simple_pov_gpt35.txt +0 -0
  132. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/personas/examples/sqldb/test.db +0 -0
  133. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/__init__.py +0 -0
  134. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/gpt_summarize.py +0 -0
  135. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/gpt_system.py +0 -0
  136. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/system/memgpt_base.txt +0 -0
  137. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/system/memgpt_chat.txt +0 -0
  138. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/system/memgpt_chat_compressed.txt +0 -0
  139. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/system/memgpt_chat_fstring.txt +0 -0
  140. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/system/memgpt_doc.txt +0 -0
  141. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/system/memgpt_gpt35_extralong.txt +0 -0
  142. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/system/memgpt_intuitive_knowledge.txt +0 -0
  143. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/system/memgpt_modified_chat.txt +0 -0
  144. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/prompts/system/memgpt_modified_o1.txt +0 -0
  145. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/providers.py +0 -0
  146. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/pytest.ini +0 -0
  147. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/agent.py +0 -0
  148. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/agents_tags.py +0 -0
  149. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/api_key.py +0 -0
  150. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/blocks_agents.py +0 -0
  151. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/embedding_config.py +0 -0
  152. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/enums.py +0 -0
  153. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/file.py +0 -0
  154. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/health.py +0 -0
  155. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/job.py +0 -0
  156. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/letta_base.py +0 -0
  157. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/letta_message.py +0 -0
  158. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/letta_request.py +0 -0
  159. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/letta_response.py +0 -0
  160. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/llm_config.py +0 -0
  161. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/memory.py +0 -0
  162. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/message.py +0 -0
  163. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/openai/chat_completion_request.py +0 -0
  164. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/openai/chat_completion_response.py +0 -0
  165. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/openai/chat_completions.py +0 -0
  166. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/openai/embedding_response.py +0 -0
  167. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/openai/openai.py +0 -0
  168. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/organization.py +0 -0
  169. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/passage.py +0 -0
  170. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/sandbox_config.py +0 -0
  171. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/source.py +0 -0
  172. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/tool_rule.py +0 -0
  173. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/usage.py +0 -0
  174. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/schemas/user.py +0 -0
  175. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/__init__.py +0 -0
  176. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/constants.py +0 -0
  177. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/generate_openapi_schema.sh +0 -0
  178. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/__init__.py +0 -0
  179. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/app.py +0 -0
  180. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/auth/__init__.py +0 -0
  181. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/auth/index.py +0 -0
  182. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/auth_token.py +0 -0
  183. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/interface.py +0 -0
  184. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/__init__.py +0 -0
  185. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/openai/__init__.py +0 -0
  186. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/openai/assistants/__init__.py +0 -0
  187. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/openai/assistants/assistants.py +0 -0
  188. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/openai/assistants/schemas.py +0 -0
  189. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/openai/assistants/threads.py +0 -0
  190. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/openai/chat_completions/__init__.py +0 -0
  191. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +0 -0
  192. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/__init__.py +0 -0
  193. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/blocks.py +0 -0
  194. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/health.py +0 -0
  195. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/jobs.py +0 -0
  196. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/llms.py +0 -0
  197. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/organizations.py +0 -0
  198. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/sandbox_configs.py +0 -0
  199. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/sources.py +0 -0
  200. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/routers/v1/users.py +0 -0
  201. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/static_files.py +0 -0
  202. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/rest_api/utils.py +0 -0
  203. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/startup.sh +0 -0
  204. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/static_files/assets/index-3ab03d5b.css +0 -0
  205. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/static_files/assets/index-9fa459a2.js +0 -0
  206. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/static_files/favicon.ico +0 -0
  207. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/static_files/index.html +0 -0
  208. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/static_files/memgpt_logo_transparent.png +0 -0
  209. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/utils.py +0 -0
  210. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/ws_api/__init__.py +0 -0
  211. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/ws_api/example_client.py +0 -0
  212. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/ws_api/interface.py +0 -0
  213. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/ws_api/protocol.py +0 -0
  214. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/server/ws_api/server.py +0 -0
  215. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/__init__.py +0 -0
  216. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/agents_tags_manager.py +0 -0
  217. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/organization_manager.py +0 -0
  218. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/sandbox_config_manager.py +0 -0
  219. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/source_manager.py +0 -0
  220. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/tool_execution_sandbox.py +0 -0
  221. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/tool_sandbox_env/.gitkeep +0 -0
  222. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/services/user_manager.py +0 -0
  223. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/settings.py +0 -0
  224. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/streaming_interface.py +0 -0
  225. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/streaming_utils.py +0 -0
  226. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/system.py +0 -0
  227. {letta_nightly-0.5.4.dev20241125104219 → letta_nightly-0.5.4.dev20241127104220}/letta/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: letta-nightly
3
- Version: 0.5.4.dev20241125104219
3
+ Version: 0.5.4.dev20241127104220
4
4
  Summary: Create LLM agents with long-term memory and custom tools
5
5
  License: Apache License
6
6
  Author: Letta Team
@@ -1325,6 +1325,12 @@ class Agent(BaseAgent):
1325
1325
 
1326
1326
  def update_state(self) -> AgentState:
1327
1327
  message_ids = [msg.id for msg in self._messages]
1328
+
1329
+ # Assert that these are all strings
1330
+ if any(not isinstance(m_id, str) for m_id in message_ids):
1331
+ warnings.warn(f"Non-string message IDs found in agent state: {message_ids}")
1332
+ message_ids = [m_id for m_id in message_ids if isinstance(m_id, str)]
1333
+
1328
1334
  assert isinstance(self.memory, Memory), f"Memory is not a Memory object: {type(self.memory)}"
1329
1335
 
1330
1336
  # override any fields that may have been updated
@@ -136,7 +136,7 @@ def add_tool(
136
136
  func = eval(func_def.name)
137
137
 
138
138
  # 4. Add or update the tool
139
- tool = client.create_tool(func=func, name=name, tags=tags, update=update)
139
+ tool = client.create_or_update_tool(func=func, name=name, tags=tags, update=update)
140
140
  print(f"Tool {tool.name} added successfully")
141
141
 
142
142
 
@@ -211,6 +211,14 @@ class AbstractClient(object):
211
211
  ) -> Tool:
212
212
  raise NotImplementedError
213
213
 
214
+ def create_or_update_tool(
215
+ self,
216
+ func,
217
+ name: Optional[str] = None,
218
+ tags: Optional[List[str]] = None,
219
+ ) -> Tool:
220
+ raise NotImplementedError
221
+
214
222
  def update_tool(
215
223
  self,
216
224
  id: str,
@@ -532,7 +540,7 @@ class RESTClient(AbstractClient):
532
540
  # add memory tools
533
541
  memory_functions = get_memory_functions(memory)
534
542
  for func_name, func in memory_functions.items():
535
- tool = self.create_tool(func, name=func_name, tags=["memory", "letta-base"])
543
+ tool = self.create_or_update_tool(func, name=func_name, tags=["memory", "letta-base"])
536
544
  tool_names.append(tool.name)
537
545
 
538
546
  # check if default configs are provided
@@ -1440,18 +1448,39 @@ class RESTClient(AbstractClient):
1440
1448
  Returns:
1441
1449
  tool (Tool): The created tool.
1442
1450
  """
1451
+ source_code = parse_source_code(func)
1452
+ source_type = "python"
1443
1453
 
1444
- # TODO: check tool update code
1445
- # TODO: check if tool already exists
1454
+ # call server function
1455
+ request = ToolCreate(source_type=source_type, source_code=source_code, name=name, tags=tags)
1456
+ response = requests.post(f"{self.base_url}/{self.api_prefix}/tools", json=request.model_dump(), headers=self.headers)
1457
+ if response.status_code != 200:
1458
+ raise ValueError(f"Failed to create tool: {response.text}")
1459
+ return Tool(**response.json())
1446
1460
 
1447
- # TODO: how to load modules?
1448
- # parse source code/schema
1461
+ def create_or_update_tool(
1462
+ self,
1463
+ func: Callable,
1464
+ name: Optional[str] = None,
1465
+ tags: Optional[List[str]] = None,
1466
+ ) -> Tool:
1467
+ """
1468
+ Creates or updates a tool. This stores the source code of function on the server, so that the server can execute the function and generate an OpenAI JSON schemas for it when using with an agent.
1469
+
1470
+ Args:
1471
+ func (callable): The function to create a tool for.
1472
+ name: (str): Name of the tool (must be unique per-user.)
1473
+ tags (Optional[List[str]], optional): Tags for the tool. Defaults to None.
1474
+
1475
+ Returns:
1476
+ tool (Tool): The created tool.
1477
+ """
1449
1478
  source_code = parse_source_code(func)
1450
1479
  source_type = "python"
1451
1480
 
1452
1481
  # call server function
1453
1482
  request = ToolCreate(source_type=source_type, source_code=source_code, name=name, tags=tags)
1454
- response = requests.post(f"{self.base_url}/{self.api_prefix}/tools", json=request.model_dump(), headers=self.headers)
1483
+ response = requests.put(f"{self.base_url}/{self.api_prefix}/tools", json=request.model_dump(), headers=self.headers)
1455
1484
  if response.status_code != 200:
1456
1485
  raise ValueError(f"Failed to create tool: {response.text}")
1457
1486
  return Tool(**response.json())
@@ -1489,45 +1518,6 @@ class RESTClient(AbstractClient):
1489
1518
  raise ValueError(f"Failed to update tool: {response.text}")
1490
1519
  return Tool(**response.json())
1491
1520
 
1492
- # def create_tool(
1493
- # self,
1494
- # func,
1495
- # name: Optional[str] = None,
1496
- # update: Optional[bool] = True, # TODO: actually use this
1497
- # tags: Optional[List[str]] = None,
1498
- # ):
1499
- # """Create a tool
1500
-
1501
- # Args:
1502
- # func (callable): The function to create a tool for.
1503
- # tags (Optional[List[str]], optional): Tags for the tool. Defaults to None.
1504
- # update (bool, optional): Update the tool if it already exists. Defaults to True.
1505
-
1506
- # Returns:
1507
- # Tool object
1508
- # """
1509
-
1510
- # # TODO: check if tool already exists
1511
- # # TODO: how to load modules?
1512
- # # parse source code/schema
1513
- # source_code = parse_source_code(func)
1514
- # json_schema = generate_schema(func, name)
1515
- # source_type = "python"
1516
- # json_schema["name"]
1517
-
1518
- # # create data
1519
- # data = {"source_code": source_code, "source_type": source_type, "tags": tags, "json_schema": json_schema, "update": update}
1520
- # try:
1521
- # CreateToolRequest(**data) # validate data
1522
- # except Exception as e:
1523
- # raise ValueError(f"Failed to create tool: {e}, invalid input {data}")
1524
-
1525
- # # make REST request
1526
- # response = requests.post(f"{self.base_url}/{self.api_prefix}/tools", json=data, headers=self.headers)
1527
- # if response.status_code != 200:
1528
- # raise ValueError(f"Failed to create tool: {response.text}")
1529
- # return ToolModel(**response.json())
1530
-
1531
1521
  def list_tools(self, cursor: Optional[str] = None, limit: Optional[int] = 50) -> List[Tool]:
1532
1522
  """
1533
1523
  List available tools for the user.
@@ -1977,7 +1967,7 @@ class LocalClient(AbstractClient):
1977
1967
  # add memory tools
1978
1968
  memory_functions = get_memory_functions(memory)
1979
1969
  for func_name, func in memory_functions.items():
1980
- tool = self.create_tool(func, name=func_name, tags=["memory", "letta-base"])
1970
+ tool = self.create_or_update_tool(func, name=func_name, tags=["memory", "letta-base"])
1981
1971
  tool_names.append(tool.name)
1982
1972
 
1983
1973
  self.interface.clear()
@@ -2573,7 +2563,6 @@ class LocalClient(AbstractClient):
2573
2563
  tool_create = ToolCreate.from_composio(action=action)
2574
2564
  return self.server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=self.user)
2575
2565
 
2576
- # TODO: Use the above function `add_tool` here as there is duplicate logic
2577
2566
  def create_tool(
2578
2567
  self,
2579
2568
  func,
@@ -2601,6 +2590,42 @@ class LocalClient(AbstractClient):
2601
2590
  if not tags:
2602
2591
  tags = []
2603
2592
 
2593
+ # call server function
2594
+ return self.server.tool_manager.create_tool(
2595
+ Tool(
2596
+ source_type=source_type,
2597
+ source_code=source_code,
2598
+ name=name,
2599
+ tags=tags,
2600
+ description=description,
2601
+ ),
2602
+ actor=self.user,
2603
+ )
2604
+
2605
+ def create_or_update_tool(
2606
+ self,
2607
+ func,
2608
+ name: Optional[str] = None,
2609
+ tags: Optional[List[str]] = None,
2610
+ description: Optional[str] = None,
2611
+ ) -> Tool:
2612
+ """
2613
+ Creates or updates a tool. This stores the source code of function on the server, so that the server can execute the function and generate an OpenAI JSON schemas for it when using with an agent.
2614
+
2615
+ Args:
2616
+ func (callable): The function to create a tool for.
2617
+ name: (str): Name of the tool (must be unique per-user.)
2618
+ tags (Optional[List[str]], optional): Tags for the tool. Defaults to None.
2619
+ description (str, optional): The description.
2620
+
2621
+ Returns:
2622
+ tool (Tool): The created tool.
2623
+ """
2624
+ source_code = parse_source_code(func)
2625
+ source_type = "python"
2626
+ if not tags:
2627
+ tags = []
2628
+
2604
2629
  # call server function
2605
2630
  return self.server.tool_manager.create_or_update_tool(
2606
2631
  Tool(
@@ -10,6 +10,18 @@ class LettaError(Exception):
10
10
  """Base class for all Letta related errors."""
11
11
 
12
12
 
13
+ class LettaToolCreateError(LettaError):
14
+ """Error raised when a tool cannot be created."""
15
+
16
+ default_error_message = "Error creating tool."
17
+
18
+ def __init__(self, message=None):
19
+ if message is None:
20
+ message = self.default_error_message
21
+ self.message = message
22
+ super().__init__(self.message)
23
+
24
+
13
25
  class LLMError(LettaError):
14
26
  pass
15
27
 
@@ -3,9 +3,10 @@ import inspect
3
3
  import os
4
4
  from textwrap import dedent # remove indentation
5
5
  from types import ModuleType
6
- from typing import Optional, List
6
+ from typing import Dict, List, Optional
7
7
 
8
8
  from letta.constants import CLI_WARNING_PREFIX
9
+ from letta.errors import LettaToolCreateError
9
10
  from letta.functions.schema_generator import generate_schema
10
11
 
11
12
 
@@ -13,10 +14,7 @@ def derive_openai_json_schema(source_code: str, name: Optional[str] = None) -> d
13
14
  # auto-generate openai schema
14
15
  try:
15
16
  # Define a custom environment with necessary imports
16
- env = {
17
- "Optional": Optional, # Add any other required imports here
18
- "List": List
19
- }
17
+ env = {"Optional": Optional, "List": List, "Dict": Dict} # Add any other required imports here
20
18
 
21
19
  env.update(globals())
22
20
  exec(source_code, env)
@@ -29,7 +27,7 @@ def derive_openai_json_schema(source_code: str, name: Optional[str] = None) -> d
29
27
  json_schema = generate_schema(func, name=name)
30
28
  return json_schema
31
29
  except Exception as e:
32
- raise RuntimeError(f"Failed to execute source code: {e}")
30
+ raise LettaToolCreateError(f"Failed to derive JSON schema from source code: {e}")
33
31
 
34
32
 
35
33
  def parse_source_code(func) -> str:
@@ -131,11 +131,12 @@ def generate_schema(function, name: Optional[str] = None, description: Optional[
131
131
  else:
132
132
  # Add parameter details to the schema
133
133
  param_doc = next((d for d in docstring.params if d.arg_name == param.name), None)
134
- schema["parameters"]["properties"][param.name] = {
135
- # "type": "string" if param.annotation == str else str(param.annotation),
136
- "type": type_to_json_schema_type(param.annotation) if param.annotation != inspect.Parameter.empty else "string",
137
- "description": param_doc.description,
138
- }
134
+ if param_doc:
135
+ schema["parameters"]["properties"][param.name] = {
136
+ # "type": "string" if param.annotation == str else str(param.annotation),
137
+ "type": type_to_json_schema_type(param.annotation) if param.annotation != inspect.Parameter.empty else "string",
138
+ "description": param_doc.description,
139
+ }
139
140
  if param.default == inspect.Parameter.empty:
140
141
  schema["parameters"]["required"].append(param.name)
141
142
 
@@ -25,6 +25,7 @@ from letta.schemas.tool_rule import (
25
25
  ToolRule,
26
26
  )
27
27
  from letta.schemas.user import User
28
+ from letta.services.per_agent_lock_manager import PerAgentLockManager
28
29
  from letta.settings import settings
29
30
  from letta.utils import enforce_types, get_utc_time, printd
30
31
 
@@ -383,7 +384,11 @@ class MetadataStore:
383
384
  session.commit()
384
385
 
385
386
  @enforce_types
386
- def delete_agent(self, agent_id: str):
387
+ def delete_agent(self, agent_id: str, per_agent_lock_manager: PerAgentLockManager):
388
+ # TODO: Remove this once Agent is on the ORM
389
+ # TODO: To prevent unbounded growth
390
+ per_agent_lock_manager.clear_lock(agent_id)
391
+
387
392
  with self.session_maker() as session:
388
393
 
389
394
  # delete agents
@@ -10,7 +10,7 @@ from letta.schemas.block import Block as PydanticBlock
10
10
  from letta.schemas.block import Human, Persona
11
11
 
12
12
  if TYPE_CHECKING:
13
- from letta.orm.organization import Organization
13
+ from letta.orm import BlocksAgents, Organization
14
14
 
15
15
 
16
16
  class Block(OrganizationMixin, SqlalchemyBase):
@@ -35,6 +35,7 @@ class Block(OrganizationMixin, SqlalchemyBase):
35
35
 
36
36
  # relationships
37
37
  organization: Mapped[Optional["Organization"]] = relationship("Organization")
38
+ blocks_agents: Mapped[list["BlocksAgents"]] = relationship("BlocksAgents", back_populates="block", cascade="all, delete")
38
39
 
39
40
  def to_pydantic(self) -> Type:
40
41
  match self.label:
@@ -1,5 +1,5 @@
1
1
  from sqlalchemy import ForeignKey, ForeignKeyConstraint, String, UniqueConstraint
2
- from sqlalchemy.orm import Mapped, mapped_column
2
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
3
3
 
4
4
  from letta.orm.sqlalchemy_base import SqlalchemyBase
5
5
  from letta.schemas.blocks_agents import BlocksAgents as PydanticBlocksAgents
@@ -27,3 +27,6 @@ class BlocksAgents(SqlalchemyBase):
27
27
  agent_id: Mapped[str] = mapped_column(String, ForeignKey("agents.id"), primary_key=True)
28
28
  block_id: Mapped[str] = mapped_column(String, primary_key=True)
29
29
  block_label: Mapped[str] = mapped_column(String, primary_key=True)
30
+
31
+ # relationships
32
+ block: Mapped["Block"] = relationship("Block", back_populates="blocks_agents")
@@ -0,0 +1,14 @@
1
+ class NoResultFound(Exception):
2
+ """A record or records cannot be found given the provided search params"""
3
+
4
+
5
+ class MalformedIdError(Exception):
6
+ """An id not in the right format, most likely violating uuid4 format."""
7
+
8
+
9
+ class UniqueConstraintViolationError(ValueError):
10
+ """Custom exception for unique constraint violations."""
11
+
12
+
13
+ class ForeignKeyConstraintViolationError(ValueError):
14
+ """Custom exception for foreign key constraint violations."""
@@ -1,11 +1,16 @@
1
1
  from typing import TYPE_CHECKING, List, Literal, Optional, Type
2
2
 
3
3
  from sqlalchemy import String, select
4
+ from sqlalchemy.exc import DBAPIError
4
5
  from sqlalchemy.orm import Mapped, mapped_column
5
6
 
6
7
  from letta.log import get_logger
7
8
  from letta.orm.base import Base, CommonSqlalchemyMetaMixins
8
- from letta.orm.errors import NoResultFound
9
+ from letta.orm.errors import (
10
+ ForeignKeyConstraintViolationError,
11
+ NoResultFound,
12
+ UniqueConstraintViolationError,
13
+ )
9
14
 
10
15
  if TYPE_CHECKING:
11
16
  from pydantic import BaseModel
@@ -102,12 +107,14 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
102
107
 
103
108
  if actor:
104
109
  self._set_created_and_updated_by_fields(actor.id)
105
-
106
- with db_session as session:
107
- session.add(self)
108
- session.commit()
109
- session.refresh(self)
110
- return self
110
+ try:
111
+ with db_session as session:
112
+ session.add(self)
113
+ session.commit()
114
+ session.refresh(self)
115
+ return self
116
+ except DBAPIError as e:
117
+ self._handle_dbapi_error(e)
111
118
 
112
119
  def delete(self, db_session: "Session", actor: Optional["User"] = None) -> Type["SqlalchemyBase"]:
113
120
  logger.debug(f"Soft deleting {self.__class__.__name__} with ID: {self.id} with actor={actor}")
@@ -168,6 +175,51 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
168
175
  raise ValueError(f"object {actor} has no organization accessor")
169
176
  return query.where(cls.organization_id == org_id, cls.is_deleted == False)
170
177
 
178
+ @classmethod
179
+ def _handle_dbapi_error(cls, e: DBAPIError):
180
+ """Handle database errors and raise appropriate custom exceptions."""
181
+ orig = e.orig # Extract the original error from the DBAPIError
182
+ error_code = None
183
+ error_message = str(orig) if orig else str(e)
184
+ logger.info(f"Handling DBAPIError: {error_message}")
185
+
186
+ # Handle SQLite-specific errors
187
+ if "UNIQUE constraint failed" in error_message:
188
+ raise UniqueConstraintViolationError(
189
+ f"A unique constraint was violated for {cls.__name__}. Check your input for duplicates: {e}"
190
+ ) from e
191
+
192
+ if "FOREIGN KEY constraint failed" in error_message:
193
+ raise ForeignKeyConstraintViolationError(
194
+ f"A foreign key constraint was violated for {cls.__name__}. Check your input for missing or invalid references: {e}"
195
+ ) from e
196
+
197
+ # For psycopg2
198
+ if hasattr(orig, "pgcode"):
199
+ error_code = orig.pgcode
200
+ # For pg8000
201
+ elif hasattr(orig, "args") and len(orig.args) > 0:
202
+ # The first argument contains the error details as a dictionary
203
+ err_dict = orig.args[0]
204
+ if isinstance(err_dict, dict):
205
+ error_code = err_dict.get("C") # 'C' is the error code field
206
+ logger.info(f"Extracted error_code: {error_code}")
207
+
208
+ # Handle unique constraint violations
209
+ if error_code == "23505":
210
+ raise UniqueConstraintViolationError(
211
+ f"A unique constraint was violated for {cls.__name__}. Check your input for duplicates: {e}"
212
+ ) from e
213
+
214
+ # Handle foreign key violations
215
+ if error_code == "23503":
216
+ raise ForeignKeyConstraintViolationError(
217
+ f"A foreign key constraint was violated for {cls.__name__}. Check your input for missing or invalid references: {e}"
218
+ ) from e
219
+
220
+ # Re-raise for other unhandled DBAPI errors
221
+ raise
222
+
171
223
  @property
172
224
  def __pydantic_model__(self) -> Type["BaseModel"]:
173
225
  raise NotImplementedError("Sqlalchemy models must declare a __pydantic_model__ property to be convertable.")
@@ -30,7 +30,7 @@ class BaseBlock(LettaBase, validate_assignment=True):
30
30
 
31
31
  @model_validator(mode="after")
32
32
  def verify_char_limit(self) -> Self:
33
- if len(self.value) > self.limit:
33
+ if self.value and len(self.value) > self.limit:
34
34
  error_msg = f"Edit failed: Exceeds {self.limit} character limit (requested {len(self.value)}) - {str(self)}."
35
35
  raise ValueError(error_msg)
36
36
 
@@ -1,7 +1,8 @@
1
1
  from typing import Dict, List, Optional
2
2
 
3
- from pydantic import Field
3
+ from pydantic import Field, model_validator
4
4
 
5
+ from letta.functions.functions import derive_openai_json_schema
5
6
  from letta.functions.helpers import (
6
7
  generate_composio_tool_wrapper,
7
8
  generate_langchain_tool_wrapper,
@@ -44,6 +45,29 @@ class Tool(BaseTool):
44
45
  created_by_id: Optional[str] = Field(None, description="The id of the user that made this Tool.")
45
46
  last_updated_by_id: Optional[str] = Field(None, description="The id of the user that made this Tool.")
46
47
 
48
+ @model_validator(mode="after")
49
+ def populate_missing_fields(self):
50
+ """
51
+ Populate missing fields: name, description, and json_schema.
52
+ """
53
+ # Derive JSON schema if not provided
54
+ if not self.json_schema:
55
+ self.json_schema = derive_openai_json_schema(source_code=self.source_code)
56
+
57
+ # Derive name from the JSON schema if not provided
58
+ if not self.name:
59
+ # TODO: This in theory could error, but name should always be on json_schema
60
+ # TODO: Make JSON schema a typed pydantic object
61
+ self.name = self.json_schema.get("name")
62
+
63
+ # Derive description from the JSON schema if not provided
64
+ if not self.description:
65
+ # TODO: This in theory could error, but description should always be on json_schema
66
+ # TODO: Make JSON schema a typed pydantic object
67
+ self.description = self.json_schema.get("description")
68
+
69
+ return self
70
+
47
71
  def to_dict(self):
48
72
  """
49
73
  Convert tool into OpenAI representation.
@@ -475,19 +475,21 @@ async def send_message(
475
475
  """
476
476
  actor = server.get_user_or_default(user_id=user_id)
477
477
 
478
- result = await send_message_to_agent(
479
- server=server,
480
- agent_id=agent_id,
481
- user_id=actor.id,
482
- messages=request.messages,
483
- stream_steps=request.stream_steps,
484
- stream_tokens=request.stream_tokens,
485
- return_message_object=request.return_message_object,
486
- # Support for AssistantMessage
487
- use_assistant_message=request.use_assistant_message,
488
- assistant_message_function_name=request.assistant_message_function_name,
489
- assistant_message_function_kwarg=request.assistant_message_function_kwarg,
490
- )
478
+ agent_lock = server.per_agent_lock_manager.get_lock(agent_id)
479
+ async with agent_lock:
480
+ result = await send_message_to_agent(
481
+ server=server,
482
+ agent_id=agent_id,
483
+ user_id=actor.id,
484
+ messages=request.messages,
485
+ stream_steps=request.stream_steps,
486
+ stream_tokens=request.stream_tokens,
487
+ return_message_object=request.return_message_object,
488
+ # Support for AssistantMessage
489
+ use_assistant_message=request.use_assistant_message,
490
+ assistant_message_function_name=request.assistant_message_function_name,
491
+ assistant_message_function_kwarg=request.assistant_message_function_kwarg,
492
+ )
491
493
  return result
492
494
 
493
495
 
@@ -2,6 +2,8 @@ from typing import List, Optional
2
2
 
3
3
  from fastapi import APIRouter, Body, Depends, Header, HTTPException
4
4
 
5
+ from letta.errors import LettaToolCreateError
6
+ from letta.orm.errors import UniqueConstraintViolationError
5
7
  from letta.schemas.tool import Tool, ToolCreate, ToolUpdate
6
8
  from letta.server.rest_api.utils import get_letta_server
7
9
  from letta.server.server import SyncServer
@@ -13,12 +15,13 @@ router = APIRouter(prefix="/tools", tags=["tools"])
13
15
  def delete_tool(
14
16
  tool_id: str,
15
17
  server: SyncServer = Depends(get_letta_server),
18
+ user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
16
19
  ):
17
20
  """
18
21
  Delete a tool by name
19
22
  """
20
- # actor = server.get_user_or_default(user_id=user_id)
21
- server.tool_manager.delete_tool(tool_id=tool_id)
23
+ actor = server.get_user_or_default(user_id=user_id)
24
+ server.tool_manager.delete_tool_by_id(tool_id=tool_id, actor=actor)
22
25
 
23
26
 
24
27
  @router.get("/{tool_id}", response_model=Tool, operation_id="get_tool")
@@ -83,12 +86,50 @@ def create_tool(
83
86
  """
84
87
  Create a new tool
85
88
  """
86
- # Derive user and org id from actor
87
- actor = server.get_user_or_default(user_id=user_id)
89
+ try:
90
+ actor = server.get_user_or_default(user_id=user_id)
91
+ tool = Tool(**request.model_dump())
92
+ return server.tool_manager.create_tool(pydantic_tool=tool, actor=actor)
93
+ except UniqueConstraintViolationError as e:
94
+ # Log or print the full exception here for debugging
95
+ print(f"Error occurred: {e}")
96
+ clean_error_message = f"Tool with name {request.name} already exists."
97
+ raise HTTPException(status_code=409, detail=clean_error_message)
98
+ except LettaToolCreateError as e:
99
+ # HTTP 400 == Bad Request
100
+ print(f"Error occurred during tool creation: {e}")
101
+ # print the full stack trace
102
+ import traceback
103
+
104
+ print(traceback.format_exc())
105
+ raise HTTPException(status_code=400, detail=str(e))
106
+ except Exception as e:
107
+ # Catch other unexpected errors and raise an internal server error
108
+ print(f"Unexpected error occurred: {e}")
109
+ raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
110
+
88
111
 
89
- # Send request to create the tool
90
- tool = Tool(**request.model_dump())
91
- return server.tool_manager.create_or_update_tool(pydantic_tool=tool, actor=actor)
112
+ @router.put("/", response_model=Tool, operation_id="upsert_tool")
113
+ def upsert_tool(
114
+ request: ToolCreate = Body(...),
115
+ server: SyncServer = Depends(get_letta_server),
116
+ user_id: Optional[str] = Header(None, alias="user_id"),
117
+ ):
118
+ """
119
+ Create or update a tool
120
+ """
121
+ try:
122
+ actor = server.get_user_or_default(user_id=user_id)
123
+ tool = server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**request.model_dump()), actor=actor)
124
+ return tool
125
+ except UniqueConstraintViolationError as e:
126
+ # Log the error and raise a conflict exception
127
+ print(f"Unique constraint violation occurred: {e}")
128
+ raise HTTPException(status_code=409, detail=str(e))
129
+ except Exception as e:
130
+ # Catch other unexpected errors and raise an internal server error
131
+ print(f"Unexpected error occurred: {e}")
132
+ raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
92
133
 
93
134
 
94
135
  @router.patch("/{tool_id}", response_model=Tool, operation_id="update_tool")
@@ -3,6 +3,7 @@ import os
3
3
  import traceback
4
4
  import warnings
5
5
  from abc import abstractmethod
6
+ from asyncio import Lock
6
7
  from datetime import datetime
7
8
  from typing import Callable, Dict, List, Optional, Tuple, Union
8
9
 
@@ -79,6 +80,7 @@ from letta.services.agents_tags_manager import AgentsTagsManager
79
80
  from letta.services.block_manager import BlockManager
80
81
  from letta.services.blocks_agents_manager import BlocksAgentsManager
81
82
  from letta.services.organization_manager import OrganizationManager
83
+ from letta.services.per_agent_lock_manager import PerAgentLockManager
82
84
  from letta.services.sandbox_config_manager import SandboxConfigManager
83
85
  from letta.services.source_manager import SourceManager
84
86
  from letta.services.tool_manager import ToolManager
@@ -231,6 +233,9 @@ class SyncServer(Server):
231
233
 
232
234
  self.credentials = LettaCredentials.load()
233
235
 
236
+ # Locks
237
+ self.send_message_lock = Lock()
238
+
234
239
  # Initialize the metadata store
235
240
  config = LettaConfig.load()
236
241
  if settings.letta_pg_uri_no_default:
@@ -252,6 +257,9 @@ class SyncServer(Server):
252
257
  self.blocks_agents_manager = BlocksAgentsManager()
253
258
  self.sandbox_config_manager = SandboxConfigManager(tool_settings)
254
259
 
260
+ # Managers that interface with parallelism
261
+ self.per_agent_lock_manager = PerAgentLockManager()
262
+
255
263
  # Make default user and org
256
264
  if init_with_default_org_and_user:
257
265
  self.default_org = self.organization_manager.create_default_organization()
@@ -925,7 +933,7 @@ class SyncServer(Server):
925
933
  logger.exception(e)
926
934
  try:
927
935
  if agent:
928
- self.ms.delete_agent(agent_id=agent.agent_state.id)
936
+ self.ms.delete_agent(agent_id=agent.agent_state.id, per_agent_lock_manager=self.per_agent_lock_manager)
929
937
  except Exception as delete_e:
930
938
  logger.exception(f"Failed to delete_agent:\n{delete_e}")
931
939
  raise e
@@ -1522,7 +1530,7 @@ class SyncServer(Server):
1522
1530
 
1523
1531
  # Next, attempt to delete it from the actual database
1524
1532
  try:
1525
- self.ms.delete_agent(agent_id=agent_id)
1533
+ self.ms.delete_agent(agent_id=agent_id, per_agent_lock_manager=self.per_agent_lock_manager)
1526
1534
  except Exception as e:
1527
1535
  logger.exception(f"Failed to delete agent {agent_id} via ID with:\n{str(e)}")
1528
1536
  raise ValueError(f"Failed to delete agent {agent_id} in database")