letta-nightly 0.6.0.dev20241204232133__tar.gz → 0.6.1.dev20241205211219__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 (228) hide show
  1. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/PKG-INFO +1 -1
  2. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/__init__.py +1 -1
  3. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/agent.py +15 -1
  4. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/client/client.py +10 -6
  5. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/metadata.py +2 -65
  6. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/__init__.py +1 -0
  7. letta_nightly-0.6.1.dev20241205211219/letta/orm/job.py +29 -0
  8. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/sqlalchemy_base.py +29 -10
  9. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/user.py +3 -3
  10. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/job.py +9 -9
  11. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/jobs.py +18 -10
  12. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/sources.py +7 -5
  13. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/server.py +15 -45
  14. letta_nightly-0.6.1.dev20241205211219/letta/services/job_manager.py +85 -0
  15. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/tool_execution_sandbox.py +29 -5
  16. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/utils.py +19 -3
  17. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/pyproject.toml +1 -1
  18. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/LICENSE +0 -0
  19. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/README.md +0 -0
  20. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/__main__.py +0 -0
  21. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/agent_store/chroma.py +0 -0
  22. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/agent_store/db.py +0 -0
  23. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/agent_store/lancedb.py +0 -0
  24. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/agent_store/milvus.py +0 -0
  25. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/agent_store/qdrant.py +0 -0
  26. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/agent_store/storage.py +0 -0
  27. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/benchmark/benchmark.py +0 -0
  28. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/benchmark/constants.py +0 -0
  29. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/cli/cli.py +0 -0
  30. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/cli/cli_config.py +0 -0
  31. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/cli/cli_load.py +0 -0
  32. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/client/__init__.py +0 -0
  33. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/client/streaming.py +0 -0
  34. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/client/utils.py +0 -0
  35. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/config.py +0 -0
  36. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/constants.py +0 -0
  37. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/credentials.py +0 -0
  38. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/data_sources/connectors.py +0 -0
  39. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/data_sources/connectors_helper.py +0 -0
  40. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/embeddings.py +0 -0
  41. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/errors.py +0 -0
  42. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/functions/__init__.py +0 -0
  43. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/functions/function_sets/base.py +0 -0
  44. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/functions/function_sets/extras.py +0 -0
  45. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/functions/functions.py +0 -0
  46. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/functions/helpers.py +0 -0
  47. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/functions/schema_generator.py +0 -0
  48. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/helpers/__init__.py +0 -0
  49. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/helpers/tool_rule_solver.py +0 -0
  50. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/humans/__init__.py +0 -0
  51. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/humans/examples/basic.txt +0 -0
  52. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/humans/examples/cs_phd.txt +0 -0
  53. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/interface.py +0 -0
  54. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/llm_api/__init__.py +0 -0
  55. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/llm_api/anthropic.py +0 -0
  56. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/llm_api/azure_openai.py +0 -0
  57. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/llm_api/azure_openai_constants.py +0 -0
  58. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/llm_api/cohere.py +0 -0
  59. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/llm_api/google_ai.py +0 -0
  60. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/llm_api/helpers.py +0 -0
  61. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/llm_api/llm_api_tools.py +0 -0
  62. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/llm_api/mistral.py +0 -0
  63. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/llm_api/openai.py +0 -0
  64. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/README.md +0 -0
  65. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/__init__.py +0 -0
  66. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/chat_completion_proxy.py +0 -0
  67. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/constants.py +0 -0
  68. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/function_parser.py +0 -0
  69. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/grammars/__init__.py +0 -0
  70. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/grammars/gbnf_grammar_generator.py +0 -0
  71. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/grammars/json.gbnf +0 -0
  72. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/grammars/json_func_calls_with_inner_thoughts.gbnf +0 -0
  73. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/json_parser.py +0 -0
  74. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/koboldcpp/api.py +0 -0
  75. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/koboldcpp/settings.py +0 -0
  76. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llamacpp/api.py +0 -0
  77. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llamacpp/settings.py +0 -0
  78. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llm_chat_completion_wrappers/__init__.py +0 -0
  79. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llm_chat_completion_wrappers/airoboros.py +0 -0
  80. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llm_chat_completion_wrappers/chatml.py +0 -0
  81. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +0 -0
  82. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llm_chat_completion_wrappers/dolphin.py +0 -0
  83. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llm_chat_completion_wrappers/llama3.py +0 -0
  84. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llm_chat_completion_wrappers/simple_summary_wrapper.py +0 -0
  85. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llm_chat_completion_wrappers/wrapper_base.py +0 -0
  86. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/llm_chat_completion_wrappers/zephyr.py +0 -0
  87. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/lmstudio/api.py +0 -0
  88. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/lmstudio/settings.py +0 -0
  89. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/ollama/api.py +0 -0
  90. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/ollama/settings.py +0 -0
  91. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/settings/__init__.py +0 -0
  92. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/settings/deterministic_mirostat.py +0 -0
  93. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/settings/settings.py +0 -0
  94. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/settings/simple.py +0 -0
  95. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/utils.py +0 -0
  96. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/vllm/api.py +0 -0
  97. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/webui/api.py +0 -0
  98. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/webui/legacy_api.py +0 -0
  99. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/webui/legacy_settings.py +0 -0
  100. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/local_llm/webui/settings.py +0 -0
  101. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/log.py +0 -0
  102. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/main.py +0 -0
  103. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/memory.py +0 -0
  104. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/o1_agent.py +0 -0
  105. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/openai_backcompat/__init__.py +0 -0
  106. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/openai_backcompat/openai_object.py +0 -0
  107. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/__all__.py +0 -0
  108. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/agents_tags.py +0 -0
  109. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/base.py +0 -0
  110. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/block.py +0 -0
  111. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/blocks_agents.py +0 -0
  112. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/enums.py +0 -0
  113. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/errors.py +0 -0
  114. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/file.py +0 -0
  115. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/mixins.py +0 -0
  116. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/organization.py +0 -0
  117. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/sandbox_config.py +0 -0
  118. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/source.py +0 -0
  119. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/orm/tool.py +0 -0
  120. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/persistence_manager.py +0 -0
  121. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/personas/__init__.py +0 -0
  122. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/personas/examples/anna_pa.txt +0 -0
  123. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/personas/examples/google_search_persona.txt +0 -0
  124. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/personas/examples/memgpt_doc.txt +0 -0
  125. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/personas/examples/memgpt_starter.txt +0 -0
  126. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/personas/examples/o1_persona.txt +0 -0
  127. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/personas/examples/sam.txt +0 -0
  128. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/personas/examples/sam_pov.txt +0 -0
  129. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/personas/examples/sam_simple_pov_gpt35.txt +0 -0
  130. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/personas/examples/sqldb/test.db +0 -0
  131. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/__init__.py +0 -0
  132. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/gpt_summarize.py +0 -0
  133. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/gpt_system.py +0 -0
  134. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/system/memgpt_base.txt +0 -0
  135. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/system/memgpt_chat.txt +0 -0
  136. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/system/memgpt_chat_compressed.txt +0 -0
  137. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/system/memgpt_chat_fstring.txt +0 -0
  138. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/system/memgpt_doc.txt +0 -0
  139. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/system/memgpt_gpt35_extralong.txt +0 -0
  140. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/system/memgpt_intuitive_knowledge.txt +0 -0
  141. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/system/memgpt_modified_chat.txt +0 -0
  142. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/prompts/system/memgpt_modified_o1.txt +0 -0
  143. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/providers.py +0 -0
  144. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/pytest.ini +0 -0
  145. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/agent.py +0 -0
  146. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/agents_tags.py +0 -0
  147. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/api_key.py +0 -0
  148. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/block.py +0 -0
  149. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/blocks_agents.py +0 -0
  150. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/embedding_config.py +0 -0
  151. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/enums.py +0 -0
  152. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/file.py +0 -0
  153. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/health.py +0 -0
  154. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/letta_base.py +0 -0
  155. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/letta_message.py +0 -0
  156. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/letta_request.py +0 -0
  157. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/letta_response.py +0 -0
  158. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/llm_config.py +0 -0
  159. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/memory.py +0 -0
  160. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/message.py +0 -0
  161. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/openai/chat_completion_request.py +0 -0
  162. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/openai/chat_completion_response.py +0 -0
  163. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/openai/chat_completions.py +0 -0
  164. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/openai/embedding_response.py +0 -0
  165. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/openai/openai.py +0 -0
  166. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/organization.py +0 -0
  167. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/passage.py +0 -0
  168. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/sandbox_config.py +0 -0
  169. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/source.py +0 -0
  170. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/tool.py +0 -0
  171. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/tool_rule.py +0 -0
  172. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/usage.py +0 -0
  173. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/schemas/user.py +0 -0
  174. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/__init__.py +0 -0
  175. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/constants.py +0 -0
  176. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/generate_openapi_schema.sh +0 -0
  177. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/__init__.py +0 -0
  178. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/app.py +0 -0
  179. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/auth/__init__.py +0 -0
  180. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/auth/index.py +0 -0
  181. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/auth_token.py +0 -0
  182. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/interface.py +0 -0
  183. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/__init__.py +0 -0
  184. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/openai/__init__.py +0 -0
  185. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/openai/assistants/__init__.py +0 -0
  186. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/openai/assistants/assistants.py +0 -0
  187. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/openai/assistants/schemas.py +0 -0
  188. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/openai/assistants/threads.py +0 -0
  189. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/openai/chat_completions/__init__.py +0 -0
  190. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +0 -0
  191. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/__init__.py +0 -0
  192. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/agents.py +0 -0
  193. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/blocks.py +0 -0
  194. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/health.py +0 -0
  195. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/llms.py +0 -0
  196. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/organizations.py +0 -0
  197. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/sandbox_configs.py +0 -0
  198. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/tools.py +0 -0
  199. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/routers/v1/users.py +0 -0
  200. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/static_files.py +0 -0
  201. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/rest_api/utils.py +0 -0
  202. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/startup.sh +0 -0
  203. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/static_files/assets/index-3ab03d5b.css +0 -0
  204. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/static_files/assets/index-9fa459a2.js +0 -0
  205. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/static_files/favicon.ico +0 -0
  206. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/static_files/index.html +0 -0
  207. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/static_files/memgpt_logo_transparent.png +0 -0
  208. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/utils.py +0 -0
  209. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/ws_api/__init__.py +0 -0
  210. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/ws_api/example_client.py +0 -0
  211. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/ws_api/interface.py +0 -0
  212. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/ws_api/protocol.py +0 -0
  213. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/server/ws_api/server.py +0 -0
  214. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/__init__.py +0 -0
  215. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/agents_tags_manager.py +0 -0
  216. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/block_manager.py +0 -0
  217. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/blocks_agents_manager.py +0 -0
  218. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/organization_manager.py +0 -0
  219. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/per_agent_lock_manager.py +0 -0
  220. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/sandbox_config_manager.py +0 -0
  221. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/source_manager.py +0 -0
  222. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/tool_manager.py +0 -0
  223. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/tool_sandbox_env/.gitkeep +0 -0
  224. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/services/user_manager.py +0 -0
  225. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/settings.py +0 -0
  226. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/streaming_interface.py +0 -0
  227. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/streaming_utils.py +0 -0
  228. {letta_nightly-0.6.0.dev20241204232133 → letta_nightly-0.6.1.dev20241205211219}/letta/system.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: letta-nightly
3
- Version: 0.6.0.dev20241204232133
3
+ Version: 0.6.1.dev20241205211219
4
4
  Summary: Create LLM agents with long-term memory and custom tools
5
5
  License: Apache License
6
6
  Author: Letta Team
@@ -1,4 +1,4 @@
1
- __version__ = "0.6.0"
1
+ __version__ = "0.6.1"
2
2
 
3
3
  # import clients
4
4
  from letta.client.client import LocalClient, RESTClient, create_client
@@ -1253,9 +1253,23 @@ class Agent(BaseAgent):
1253
1253
  self._messages = new_messages
1254
1254
 
1255
1255
  def rebuild_system_prompt(self, force=False, update_timestamp=True):
1256
- """Rebuilds the system message with the latest memory object and any shared memory block updates"""
1256
+ """Rebuilds the system message with the latest memory object and any shared memory block updates
1257
+
1258
+ Updates to core memory blocks should trigger a "rebuild", which itself will create a new message object
1259
+
1260
+ Updates to the memory header should *not* trigger a rebuild, since that will simply flood recall storage with excess messages
1261
+ """
1262
+
1257
1263
  curr_system_message = self.messages[0] # this is the system + memory bank, not just the system prompt
1258
1264
 
1265
+ # note: we only update the system prompt if the core memory is changed
1266
+ # this means that the archival/recall memory statistics may be someout out of date
1267
+ curr_memory_str = self.agent_state.memory.compile()
1268
+ if curr_memory_str in curr_system_message["content"] and not force:
1269
+ # NOTE: could this cause issues if a block is removed? (substring match would still work)
1270
+ printd(f"Memory hasn't changed, skipping system prompt rebuild")
1271
+ return
1272
+
1259
1273
  # If the memory didn't update, we probably don't want to update the timestamp inside
1260
1274
  # For example, if we're doing a system prompt swap, this should probably be False
1261
1275
  if update_timestamp:
@@ -2859,8 +2859,12 @@ class LocalClient(AbstractClient):
2859
2859
  Returns:
2860
2860
  job (Job): Data loading job including job status and metadata
2861
2861
  """
2862
- metadata_ = {"type": "embedding", "filename": filename, "source_id": source_id}
2863
- job = self.server.create_job(user_id=self.user_id, metadata=metadata_)
2862
+ job = Job(
2863
+ user_id=self.user_id,
2864
+ status=JobStatus.created,
2865
+ metadata_={"type": "embedding", "filename": filename, "source_id": source_id},
2866
+ )
2867
+ job = self.server.job_manager.create_job(pydantic_job=job, actor=self.user)
2864
2868
 
2865
2869
  # TODO: implement blocking vs. non-blocking
2866
2870
  self.server.load_file_to_source(source_id=source_id, file_path=filename, job_id=job.id)
@@ -2870,16 +2874,16 @@ class LocalClient(AbstractClient):
2870
2874
  self.server.source_manager.delete_file(file_id, actor=self.user)
2871
2875
 
2872
2876
  def get_job(self, job_id: str):
2873
- return self.server.get_job(job_id=job_id)
2877
+ return self.server.job_manager.get_job_by_id(job_id=job_id, actor=self.user)
2874
2878
 
2875
2879
  def delete_job(self, job_id: str):
2876
- return self.server.delete_job(job_id)
2880
+ return self.server.job_manager.delete_job(job_id=job_id, actor=self.user)
2877
2881
 
2878
2882
  def list_jobs(self):
2879
- return self.server.list_jobs(user_id=self.user_id)
2883
+ return self.server.job_manager.list_jobs(actor=self.user)
2880
2884
 
2881
2885
  def list_active_jobs(self):
2882
- return self.server.list_active_jobs(user_id=self.user_id)
2886
+ return self.server.job_manager.list_jobs(actor=self.user, statuses=[JobStatus.created, JobStatus.running])
2883
2887
 
2884
2888
  def create_source(self, name: str, embedding_config: Optional[EmbeddingConfig] = None) -> Source:
2885
2889
  """
@@ -12,15 +12,14 @@ from letta.orm.base import Base
12
12
  from letta.schemas.agent import PersistedAgentState
13
13
  from letta.schemas.api_key import APIKey
14
14
  from letta.schemas.embedding_config import EmbeddingConfig
15
- from letta.schemas.enums import JobStatus, ToolRuleType
16
- from letta.schemas.job import Job
15
+ from letta.schemas.enums import ToolRuleType
17
16
  from letta.schemas.llm_config import LLMConfig
18
17
  from letta.schemas.openai.chat_completions import ToolCall, ToolCallFunction
19
18
  from letta.schemas.tool_rule import ChildToolRule, InitToolRule, TerminalToolRule
20
19
  from letta.schemas.user import User
21
20
  from letta.services.per_agent_lock_manager import PerAgentLockManager
22
21
  from letta.settings import settings
23
- from letta.utils import enforce_types, get_utc_time, printd
22
+ from letta.utils import enforce_types, printd
24
23
 
25
24
 
26
25
  class LLMConfigColumn(TypeDecorator):
@@ -258,31 +257,6 @@ class AgentSourceMappingModel(Base):
258
257
  return f"<AgentSourceMapping(user_id='{self.user_id}', agent_id='{self.agent_id}', source_id='{self.source_id}')>"
259
258
 
260
259
 
261
- class JobModel(Base):
262
- __tablename__ = "jobs"
263
- __table_args__ = {"extend_existing": True}
264
-
265
- id = Column(String, primary_key=True)
266
- user_id = Column(String)
267
- status = Column(String, default=JobStatus.pending)
268
- created_at = Column(DateTime(timezone=True), server_default=func.now())
269
- completed_at = Column(DateTime(timezone=True), onupdate=func.now())
270
- metadata_ = Column(JSON)
271
-
272
- def __repr__(self) -> str:
273
- return f"<Job(id='{self.id}', status='{self.status}')>"
274
-
275
- def to_record(self):
276
- return Job(
277
- id=self.id,
278
- user_id=self.user_id,
279
- status=self.status,
280
- created_at=self.created_at,
281
- completed_at=self.completed_at,
282
- metadata_=self.metadata_,
283
- )
284
-
285
-
286
260
  class MetadataStore:
287
261
  uri: Optional[str] = None
288
262
 
@@ -455,40 +429,3 @@ class MetadataStore:
455
429
  AgentSourceMappingModel.agent_id == agent_id, AgentSourceMappingModel.source_id == source_id
456
430
  ).delete()
457
431
  session.commit()
458
-
459
- @enforce_types
460
- def create_job(self, job: Job):
461
- with self.session_maker() as session:
462
- session.add(JobModel(**vars(job)))
463
- session.commit()
464
-
465
- def delete_job(self, job_id: str):
466
- with self.session_maker() as session:
467
- session.query(JobModel).filter(JobModel.id == job_id).delete()
468
- session.commit()
469
-
470
- def get_job(self, job_id: str) -> Optional[Job]:
471
- with self.session_maker() as session:
472
- results = session.query(JobModel).filter(JobModel.id == job_id).all()
473
- if len(results) == 0:
474
- return None
475
- assert len(results) == 1, f"Expected 1 result, got {len(results)}"
476
- return results[0].to_record()
477
-
478
- def list_jobs(self, user_id: str) -> List[Job]:
479
- with self.session_maker() as session:
480
- results = session.query(JobModel).filter(JobModel.user_id == user_id).all()
481
- return [r.to_record() for r in results]
482
-
483
- def update_job(self, job: Job) -> Job:
484
- with self.session_maker() as session:
485
- session.query(JobModel).filter(JobModel.id == job.id).update(vars(job))
486
- session.commit()
487
- return Job
488
-
489
- def update_job_status(self, job_id: str, status: JobStatus):
490
- with self.session_maker() as session:
491
- session.query(JobModel).filter(JobModel.id == job_id).update({"status": status})
492
- if status == JobStatus.COMPLETED:
493
- session.query(JobModel).filter(JobModel.id == job_id).update({"completed_at": get_utc_time()})
494
- session.commit()
@@ -2,6 +2,7 @@ from letta.orm.base import Base
2
2
  from letta.orm.block import Block
3
3
  from letta.orm.blocks_agents import BlocksAgents
4
4
  from letta.orm.file import FileMetadata
5
+ from letta.orm.job import Job
5
6
  from letta.orm.organization import Organization
6
7
  from letta.orm.sandbox_config import SandboxConfig, SandboxEnvironmentVariable
7
8
  from letta.orm.source import Source
@@ -0,0 +1,29 @@
1
+ from datetime import datetime
2
+ from typing import TYPE_CHECKING, Optional
3
+
4
+ from sqlalchemy import JSON, String
5
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
6
+
7
+ from letta.orm.mixins import UserMixin
8
+ from letta.orm.sqlalchemy_base import SqlalchemyBase
9
+ from letta.schemas.enums import JobStatus
10
+ from letta.schemas.job import Job as PydanticJob
11
+
12
+ if TYPE_CHECKING:
13
+ from letta.orm.user import User
14
+
15
+
16
+ class Job(SqlalchemyBase, UserMixin):
17
+ """Jobs run in the background and are owned by a user.
18
+ Typical jobs involve loading and processing sources etc.
19
+ """
20
+
21
+ __tablename__ = "jobs"
22
+ __pydantic_model__ = PydanticJob
23
+
24
+ status: Mapped[JobStatus] = mapped_column(String, default=JobStatus.created, doc="The current status of the job.")
25
+ completed_at: Mapped[Optional[datetime]] = mapped_column(nullable=True, doc="The unix timestamp of when the job was completed.")
26
+ metadata_: Mapped[Optional[dict]] = mapped_column(JSON, default=lambda: {}, doc="The metadata of the job.")
27
+
28
+ # relationships
29
+ user: Mapped["User"] = relationship("User", back_populates="jobs")
@@ -31,24 +31,43 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
31
31
  def list(
32
32
  cls, *, db_session: "Session", cursor: Optional[str] = None, limit: Optional[int] = 50, **kwargs
33
33
  ) -> List[Type["SqlalchemyBase"]]:
34
- """List records with optional cursor (for pagination) and limit."""
35
- logger.debug(f"Listing {cls.__name__} with kwarg filters {kwargs}")
36
- with db_session as session:
37
- # Start with the base query filtered by kwargs
38
- query = select(cls).filter_by(**kwargs)
34
+ """
35
+ List records with optional cursor (for pagination), limit, and automatic filtering.
36
+
37
+ Args:
38
+ db_session: The database session to use.
39
+ cursor: Optional ID to start pagination from.
40
+ limit: Maximum number of records to return.
41
+ **kwargs: Filters passed as equality conditions or iterable for IN filtering.
39
42
 
40
- # Add a cursor condition if provided
43
+ Returns:
44
+ A list of model instances matching the filters.
45
+ """
46
+ logger.debug(f"Listing {cls.__name__} with filters {kwargs}")
47
+ with db_session as session:
48
+ # Start with a base query
49
+ query = select(cls)
50
+
51
+ # Apply filtering logic
52
+ for key, value in kwargs.items():
53
+ column = getattr(cls, key)
54
+ if isinstance(value, (list, tuple, set)): # Check for iterables
55
+ query = query.where(column.in_(value))
56
+ else: # Single value for equality filtering
57
+ query = query.where(column == value)
58
+
59
+ # Apply cursor for pagination
41
60
  if cursor:
42
61
  query = query.where(cls.id > cursor)
43
62
 
44
- # Add a limit to the query if provided
45
- query = query.order_by(cls.id).limit(limit)
46
-
47
63
  # Handle soft deletes if the class has the 'is_deleted' attribute
48
64
  if hasattr(cls, "is_deleted"):
49
65
  query = query.where(cls.is_deleted == False)
50
66
 
51
- # Execute the query and return the results as a list of model instances
67
+ # Add ordering and limit
68
+ query = query.order_by(cls.id).limit(limit)
69
+
70
+ # Execute the query and return results as model instances
52
71
  return list(session.execute(query).scalars())
53
72
 
54
73
  @classmethod
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, List
2
2
 
3
3
  from sqlalchemy.orm import Mapped, mapped_column, relationship
4
4
 
@@ -7,7 +7,7 @@ from letta.orm.sqlalchemy_base import SqlalchemyBase
7
7
  from letta.schemas.user import User as PydanticUser
8
8
 
9
9
  if TYPE_CHECKING:
10
- from letta.orm.organization import Organization
10
+ from letta.orm import Job, Organization
11
11
 
12
12
 
13
13
  class User(SqlalchemyBase, OrganizationMixin):
@@ -20,10 +20,10 @@ class User(SqlalchemyBase, OrganizationMixin):
20
20
 
21
21
  # relationships
22
22
  organization: Mapped["Organization"] = relationship("Organization", back_populates="users")
23
+ jobs: Mapped[List["Job"]] = relationship("Job", back_populates="user", doc="the jobs associated with this user.")
23
24
 
24
25
  # TODO: Add this back later potentially
25
26
  # agents: Mapped[List["Agent"]] = relationship(
26
27
  # "Agent", secondary="users_agents", back_populates="users", doc="the agents associated with this user."
27
28
  # )
28
29
  # tokens: Mapped[List["Token"]] = relationship("Token", back_populates="user", doc="the tokens associated with this user.")
29
- # jobs: Mapped[List["Job"]] = relationship("Job", back_populates="user", doc="the jobs associated with this user.")
@@ -4,12 +4,13 @@ from typing import Optional
4
4
  from pydantic import Field
5
5
 
6
6
  from letta.schemas.enums import JobStatus
7
- from letta.schemas.letta_base import LettaBase
8
- from letta.utils import get_utc_time
7
+ from letta.schemas.letta_base import OrmMetadataBase
9
8
 
10
9
 
11
- class JobBase(LettaBase):
10
+ class JobBase(OrmMetadataBase):
12
11
  __id_prefix__ = "job"
12
+ status: JobStatus = Field(default=JobStatus.created, description="The status of the job.")
13
+ completed_at: Optional[datetime] = Field(None, description="The unix timestamp of when the job was completed.")
13
14
  metadata_: Optional[dict] = Field(None, description="The metadata of the job.")
14
15
 
15
16
 
@@ -27,12 +28,11 @@ class Job(JobBase):
27
28
  """
28
29
 
29
30
  id: str = JobBase.generate_id_field()
30
- status: JobStatus = Field(default=JobStatus.created, description="The status of the job.")
31
- created_at: datetime = Field(default_factory=get_utc_time, description="The unix timestamp of when the job was created.")
32
- completed_at: Optional[datetime] = Field(None, description="The unix timestamp of when the job was completed.")
33
- user_id: str = Field(..., description="The unique identifier of the user associated with the job.")
31
+ user_id: Optional[str] = Field(None, description="The unique identifier of the user associated with the job.")
34
32
 
35
33
 
36
34
  class JobUpdate(JobBase):
37
- id: str = Field(..., description="The unique identifier of the job.")
38
- status: Optional[JobStatus] = Field(..., description="The status of the job.")
35
+ status: Optional[JobStatus] = Field(None, description="The status of the job.")
36
+
37
+ class Config:
38
+ extra = "ignore" # Ignores extra fields
@@ -2,6 +2,8 @@ from typing import List, Optional
2
2
 
3
3
  from fastapi import APIRouter, Depends, Header, HTTPException, Query
4
4
 
5
+ from letta.orm.errors import NoResultFound
6
+ from letta.schemas.enums import JobStatus
5
7
  from letta.schemas.job import Job
6
8
  from letta.server.rest_api.utils import get_letta_server
7
9
  from letta.server.server import SyncServer
@@ -21,12 +23,11 @@ def list_jobs(
21
23
  actor = server.get_user_or_default(user_id=user_id)
22
24
 
23
25
  # TODO: add filtering by status
24
- jobs = server.list_jobs(user_id=actor.id)
26
+ jobs = server.job_manager.list_jobs(actor=actor)
25
27
 
26
- # TODO: eventually use ORM
27
- # results = session.query(JobModel).filter(JobModel.user_id == user_id, JobModel.metadata_["source_id"].astext == sourced_id).all()
28
28
  if source_id:
29
29
  # can't be in the ORM since we have source_id stored in the metadata_
30
+ # TODO: Probably change this
30
31
  jobs = [job for job in jobs if job.metadata_.get("source_id") == source_id]
31
32
  return jobs
32
33
 
@@ -41,32 +42,39 @@ def list_active_jobs(
41
42
  """
42
43
  actor = server.get_user_or_default(user_id=user_id)
43
44
 
44
- return server.list_active_jobs(user_id=actor.id)
45
+ return server.job_manager.list_jobs(actor=actor, statuses=[JobStatus.created, JobStatus.running])
45
46
 
46
47
 
47
48
  @router.get("/{job_id}", response_model=Job, operation_id="get_job")
48
49
  def get_job(
49
50
  job_id: str,
51
+ user_id: Optional[str] = Header(None, alias="user_id"),
50
52
  server: "SyncServer" = Depends(get_letta_server),
51
53
  ):
52
54
  """
53
55
  Get the status of a job.
54
56
  """
57
+ actor = server.get_user_or_default(user_id=user_id)
55
58
 
56
- return server.get_job(job_id=job_id)
59
+ try:
60
+ return server.job_manager.get_job_by_id(job_id=job_id, actor=actor)
61
+ except NoResultFound:
62
+ raise HTTPException(status_code=404, detail="Job not found")
57
63
 
58
64
 
59
65
  @router.delete("/{job_id}", response_model=Job, operation_id="delete_job")
60
66
  def delete_job(
61
67
  job_id: str,
68
+ user_id: Optional[str] = Header(None, alias="user_id"),
62
69
  server: "SyncServer" = Depends(get_letta_server),
63
70
  ):
64
71
  """
65
72
  Delete a job by its job_id.
66
73
  """
67
- job = server.get_job(job_id=job_id)
68
- if not job:
69
- raise HTTPException(status_code=404, detail="Job not found")
74
+ actor = server.get_user_or_default(user_id=user_id)
70
75
 
71
- server.delete_job(job_id=job_id)
72
- return job
76
+ try:
77
+ job = server.job_manager.delete_job_by_id(job_id=job_id, actor=actor)
78
+ return job
79
+ except NoResultFound:
80
+ raise HTTPException(status_code=404, detail="Job not found")
@@ -16,6 +16,7 @@ from letta.schemas.file import FileMetadata
16
16
  from letta.schemas.job import Job
17
17
  from letta.schemas.passage import Passage
18
18
  from letta.schemas.source import Source, SourceCreate, SourceUpdate
19
+ from letta.schemas.user import User
19
20
  from letta.server.rest_api.utils import get_letta_server
20
21
  from letta.server.server import SyncServer
21
22
  from letta.utils import sanitize_filename
@@ -175,13 +176,14 @@ def upload_file_to_source(
175
176
  completed_at=None,
176
177
  )
177
178
  job_id = job.id
178
- server.ms.create_job(job)
179
+ server.job_manager.create_job(job, actor=actor)
179
180
 
180
181
  # create background task
181
- background_tasks.add_task(load_file_to_source_async, server, source_id=source.id, file=file, job_id=job.id, bytes=bytes)
182
+ background_tasks.add_task(load_file_to_source_async, server, source_id=source.id, file=file, job_id=job.id, bytes=bytes, actor=actor)
182
183
 
183
184
  # return job information
184
- job = server.ms.get_job(job_id=job_id)
185
+ # Is this necessary? Can we just return the job from create_job?
186
+ job = server.job_manager.get_job_by_id(job_id=job_id, actor=actor)
185
187
  assert job is not None, "Job not found"
186
188
  return job
187
189
 
@@ -234,7 +236,7 @@ def delete_file_from_source(
234
236
  raise HTTPException(status_code=404, detail=f"File with id={file_id} not found.")
235
237
 
236
238
 
237
- def load_file_to_source_async(server: SyncServer, source_id: str, job_id: str, file: UploadFile, bytes: bytes):
239
+ def load_file_to_source_async(server: SyncServer, source_id: str, job_id: str, file: UploadFile, bytes: bytes, actor: User):
238
240
  # Create a temporary directory (deleted after the context manager exits)
239
241
  with tempfile.TemporaryDirectory() as tmpdirname:
240
242
  # Sanitize the filename
@@ -246,4 +248,4 @@ def load_file_to_source_async(server: SyncServer, source_id: str, job_id: str, f
246
248
  buffer.write(bytes)
247
249
 
248
250
  # Pass the file to load_file_to_source
249
- server.load_file_to_source(source_id, file_path, job_id)
251
+ server.load_file_to_source(source_id, file_path, job_id, actor)
@@ -6,7 +6,7 @@ import warnings
6
6
  from abc import abstractmethod
7
7
  from asyncio import Lock
8
8
  from datetime import datetime
9
- from typing import Callable, Dict, List, Optional, Tuple, Union
9
+ from typing import Callable, List, Optional, Tuple, Union
10
10
 
11
11
  from composio.client import Composio
12
12
  from composio.client.collections import ActionModel, AppModel
@@ -56,7 +56,7 @@ from letta.schemas.embedding_config import EmbeddingConfig
56
56
 
57
57
  # openai schemas
58
58
  from letta.schemas.enums import JobStatus
59
- from letta.schemas.job import Job
59
+ from letta.schemas.job import Job, JobUpdate
60
60
  from letta.schemas.letta_message import FunctionReturn, LettaMessage
61
61
  from letta.schemas.llm_config import LLMConfig
62
62
  from letta.schemas.memory import (
@@ -75,6 +75,7 @@ from letta.schemas.user import User
75
75
  from letta.services.agents_tags_manager import AgentsTagsManager
76
76
  from letta.services.block_manager import BlockManager
77
77
  from letta.services.blocks_agents_manager import BlocksAgentsManager
78
+ from letta.services.job_manager import JobManager
78
79
  from letta.services.organization_manager import OrganizationManager
79
80
  from letta.services.per_agent_lock_manager import PerAgentLockManager
80
81
  from letta.services.sandbox_config_manager import SandboxConfigManager
@@ -256,6 +257,7 @@ class SyncServer(Server):
256
257
  self.agents_tags_manager = AgentsTagsManager()
257
258
  self.sandbox_config_manager = SandboxConfigManager(tool_settings)
258
259
  self.blocks_agents_manager = BlocksAgentsManager()
260
+ self.job_manager = JobManager()
259
261
 
260
262
  # Managers that interface with parallelism
261
263
  self.per_agent_lock_manager = PerAgentLockManager()
@@ -393,6 +395,10 @@ class SyncServer(Server):
393
395
  agent_lock = self.per_agent_lock_manager.get_lock(agent_id)
394
396
  with agent_lock:
395
397
  agent_state = self.get_agent(agent_id=agent_id)
398
+ if agent_state is None:
399
+ raise ValueError(f"Agent (agent_id={agent_id}) does not exist")
400
+ elif agent_state.user_id is None:
401
+ raise ValueError(f"Agent (agent_id={agent_id}) does not have a user_id")
396
402
  actor = self.user_manager.get_user_by_id(user_id=agent_state.user_id)
397
403
 
398
404
  interface = interface or self.default_interface_factory()
@@ -880,7 +886,7 @@ class SyncServer(Server):
880
886
  in_memory_agent_state = self.get_agent(agent_state.id)
881
887
  return in_memory_agent_state
882
888
 
883
- def get_agent(self, agent_id: str) -> AgentState:
889
+ def get_agent(self, agent_id: str) -> Optional[AgentState]:
884
890
  """
885
891
  Retrieve the full agent state from the DB.
886
892
  This gathers data accross multiple tables to provide the full state of an agent, which is passed into the `Agent` object for creation.
@@ -891,6 +897,8 @@ class SyncServer(Server):
891
897
  if agent_state is None:
892
898
  # agent does not exist
893
899
  return None
900
+ if agent_state.user_id is None:
901
+ raise ValueError(f"Agent {agent_id} does not have a user_id")
894
902
  user = self.user_manager.get_user_by_id(user_id=agent_state.user_id)
895
903
 
896
904
  # construct the in-memory, full agent state - this gather data stored in different tables but that needs to be passed to `Agent`
@@ -1469,39 +1477,12 @@ class SyncServer(Server):
1469
1477
 
1470
1478
  # TODO: delete data from agent passage stores (?)
1471
1479
 
1472
- def create_job(self, user_id: str, metadata: Optional[Dict] = None) -> Job:
1473
- """Create a new job"""
1474
- job = Job(
1475
- user_id=user_id,
1476
- status=JobStatus.created,
1477
- metadata_=metadata,
1478
- )
1479
- self.ms.create_job(job)
1480
- return job
1481
-
1482
- def delete_job(self, job_id: str):
1483
- """Delete a job"""
1484
- self.ms.delete_job(job_id)
1485
-
1486
- def get_job(self, job_id: str) -> Job:
1487
- """Get a job"""
1488
- return self.ms.get_job(job_id)
1489
-
1490
- def list_jobs(self, user_id: str) -> List[Job]:
1491
- """List all jobs for a user"""
1492
- return self.ms.list_jobs(user_id=user_id)
1493
-
1494
- def list_active_jobs(self, user_id: str) -> List[Job]:
1495
- """List all active jobs for a user"""
1496
- jobs = self.ms.list_jobs(user_id=user_id)
1497
- return [job for job in jobs if job.status in [JobStatus.created, JobStatus.running]]
1498
-
1499
- def load_file_to_source(self, source_id: str, file_path: str, job_id: str) -> Job:
1480
+ def load_file_to_source(self, source_id: str, file_path: str, job_id: str, actor: User) -> Job:
1500
1481
 
1501
1482
  # update job
1502
- job = self.ms.get_job(job_id)
1483
+ job = self.job_manager.get_job_by_id(job_id, actor=actor)
1503
1484
  job.status = JobStatus.running
1504
- self.ms.update_job(job)
1485
+ self.job_manager.update_job_by_id(job_id=job_id, job_update=JobUpdate(**job.model_dump()), actor=actor)
1505
1486
 
1506
1487
  # try:
1507
1488
  from letta.data_sources.connectors import DirectoryConnector
@@ -1509,23 +1490,12 @@ class SyncServer(Server):
1509
1490
  source = self.source_manager.get_source_by_id(source_id=source_id)
1510
1491
  connector = DirectoryConnector(input_files=[file_path])
1511
1492
  num_passages, num_documents = self.load_data(user_id=source.created_by_id, source_name=source.name, connector=connector)
1512
- # except Exception as e:
1513
- # # job failed with error
1514
- # error = str(e)
1515
- # print(error)
1516
- # job.status = JobStatus.failed
1517
- # job.metadata_["error"] = error
1518
- # self.ms.update_job(job)
1519
- # # TODO: delete any associated passages/files?
1520
-
1521
- # # return failed job
1522
- # return job
1523
1493
 
1524
1494
  # update job status
1525
1495
  job.status = JobStatus.completed
1526
1496
  job.metadata_["num_passages"] = num_passages
1527
1497
  job.metadata_["num_documents"] = num_documents
1528
- self.ms.update_job(job)
1498
+ self.job_manager.update_job_by_id(job_id=job_id, job_update=JobUpdate(**job.model_dump()), actor=actor)
1529
1499
 
1530
1500
  return job
1531
1501
 
@@ -0,0 +1,85 @@
1
+ from typing import List, Optional
2
+
3
+ from letta.orm.job import Job as JobModel
4
+ from letta.schemas.enums import JobStatus
5
+ from letta.schemas.job import Job as PydanticJob
6
+ from letta.schemas.job import JobUpdate
7
+ from letta.schemas.user import User as PydanticUser
8
+ from letta.utils import enforce_types, get_utc_time
9
+
10
+
11
+ class JobManager:
12
+ """Manager class to handle business logic related to Jobs."""
13
+
14
+ def __init__(self):
15
+ # Fetching the db_context similarly as in OrganizationManager
16
+ from letta.server.server import db_context
17
+
18
+ self.session_maker = db_context
19
+
20
+ @enforce_types
21
+ def create_job(self, pydantic_job: PydanticJob, actor: PydanticUser) -> PydanticJob:
22
+ """Create a new job based on the JobCreate schema."""
23
+ with self.session_maker() as session:
24
+ # Associate the job with the user
25
+ pydantic_job.user_id = actor.id
26
+ job_data = pydantic_job.model_dump()
27
+ job = JobModel(**job_data)
28
+ job.create(session, actor=actor) # Save job in the database
29
+ return job.to_pydantic()
30
+
31
+ @enforce_types
32
+ def update_job_by_id(self, job_id: str, job_update: JobUpdate, actor: PydanticUser) -> PydanticJob:
33
+ """Update a job by its ID with the given JobUpdate object."""
34
+ with self.session_maker() as session:
35
+ # Fetch the job by ID
36
+ job = JobModel.read(db_session=session, identifier=job_id) # TODO: Add this later , actor=actor)
37
+
38
+ # Update job attributes with only the fields that were explicitly set
39
+ update_data = job_update.model_dump(exclude_unset=True, exclude_none=True)
40
+
41
+ # Automatically update the completion timestamp if status is set to 'completed'
42
+ if update_data.get("status") == JobStatus.completed and not job.completed_at:
43
+ job.completed_at = get_utc_time()
44
+
45
+ for key, value in update_data.items():
46
+ setattr(job, key, value)
47
+
48
+ # Save the updated job to the database
49
+ return job.update(db_session=session) # TODO: Add this later , actor=actor)
50
+
51
+ @enforce_types
52
+ def get_job_by_id(self, job_id: str, actor: PydanticUser) -> PydanticJob:
53
+ """Fetch a job by its ID."""
54
+ with self.session_maker() as session:
55
+ # Retrieve job by ID using the Job model's read method
56
+ job = JobModel.read(db_session=session, identifier=job_id) # TODO: Add this later , actor=actor)
57
+ return job.to_pydantic()
58
+
59
+ @enforce_types
60
+ def list_jobs(
61
+ self, actor: PydanticUser, cursor: Optional[str] = None, limit: Optional[int] = 50, statuses: Optional[List[JobStatus]] = None
62
+ ) -> List[PydanticJob]:
63
+ """List all jobs with optional pagination and status filter."""
64
+ with self.session_maker() as session:
65
+ filter_kwargs = {"user_id": actor.id}
66
+
67
+ # Add status filter if provided
68
+ if statuses:
69
+ filter_kwargs["status"] = statuses
70
+
71
+ jobs = JobModel.list(
72
+ db_session=session,
73
+ cursor=cursor,
74
+ limit=limit,
75
+ **filter_kwargs,
76
+ )
77
+ return [job.to_pydantic() for job in jobs]
78
+
79
+ @enforce_types
80
+ def delete_job_by_id(self, job_id: str, actor: PydanticUser) -> PydanticJob:
81
+ """Delete a job by its ID."""
82
+ with self.session_maker() as session:
83
+ job = JobModel.read(db_session=session, identifier=job_id) # TODO: Add this later , actor=actor)
84
+ job.hard_delete(db_session=session) # TODO: Add this later , actor=actor)
85
+ return job.to_pydantic()