letta-nightly 0.5.4.dev20241130104041__tar.gz → 0.5.4.dev20241201104110__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.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/PKG-INFO +1 -1
  2. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/agent.py +45 -44
  3. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/functions/functions.py +40 -9
  4. letta_nightly-0.5.4.dev20241201104110/letta/functions/schema_generator.py +477 -0
  5. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/llm_api/helpers.py +99 -5
  6. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/llm_api/openai.py +8 -2
  7. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/utils.py +1 -1
  8. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/app.py +1 -1
  9. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/tool_execution_sandbox.py +21 -7
  10. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/pyproject.toml +1 -1
  11. letta_nightly-0.5.4.dev20241130104041/letta/functions/schema_generator.py +0 -237
  12. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/LICENSE +0 -0
  13. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/README.md +0 -0
  14. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/__init__.py +0 -0
  15. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/__main__.py +0 -0
  16. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/agent_store/chroma.py +0 -0
  17. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/agent_store/db.py +0 -0
  18. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/agent_store/lancedb.py +0 -0
  19. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/agent_store/milvus.py +0 -0
  20. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/agent_store/qdrant.py +0 -0
  21. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/agent_store/storage.py +0 -0
  22. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/benchmark/benchmark.py +0 -0
  23. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/benchmark/constants.py +0 -0
  24. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/cli/cli.py +0 -0
  25. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/cli/cli_config.py +0 -0
  26. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/cli/cli_load.py +0 -0
  27. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/client/__init__.py +0 -0
  28. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/client/client.py +0 -0
  29. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/client/streaming.py +0 -0
  30. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/client/utils.py +0 -0
  31. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/config.py +0 -0
  32. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/constants.py +0 -0
  33. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/credentials.py +0 -0
  34. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/data_sources/connectors.py +0 -0
  35. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/data_sources/connectors_helper.py +0 -0
  36. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/embeddings.py +0 -0
  37. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/errors.py +0 -0
  38. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/functions/__init__.py +0 -0
  39. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/functions/function_sets/base.py +0 -0
  40. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/functions/function_sets/extras.py +0 -0
  41. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/functions/helpers.py +0 -0
  42. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/helpers/__init__.py +0 -0
  43. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/helpers/tool_rule_solver.py +0 -0
  44. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/humans/__init__.py +0 -0
  45. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/humans/examples/basic.txt +0 -0
  46. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/humans/examples/cs_phd.txt +0 -0
  47. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/interface.py +0 -0
  48. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/llm_api/__init__.py +0 -0
  49. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/llm_api/anthropic.py +0 -0
  50. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/llm_api/azure_openai.py +0 -0
  51. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/llm_api/azure_openai_constants.py +0 -0
  52. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/llm_api/cohere.py +0 -0
  53. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/llm_api/google_ai.py +0 -0
  54. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/llm_api/llm_api_tools.py +0 -0
  55. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/llm_api/mistral.py +0 -0
  56. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/README.md +0 -0
  57. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/__init__.py +0 -0
  58. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/chat_completion_proxy.py +0 -0
  59. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/constants.py +0 -0
  60. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/function_parser.py +0 -0
  61. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/grammars/__init__.py +0 -0
  62. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/grammars/gbnf_grammar_generator.py +0 -0
  63. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/grammars/json.gbnf +0 -0
  64. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/grammars/json_func_calls_with_inner_thoughts.gbnf +0 -0
  65. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/json_parser.py +0 -0
  66. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/koboldcpp/api.py +0 -0
  67. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/koboldcpp/settings.py +0 -0
  68. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llamacpp/api.py +0 -0
  69. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llamacpp/settings.py +0 -0
  70. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llm_chat_completion_wrappers/__init__.py +0 -0
  71. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llm_chat_completion_wrappers/airoboros.py +0 -0
  72. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llm_chat_completion_wrappers/chatml.py +0 -0
  73. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +0 -0
  74. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llm_chat_completion_wrappers/dolphin.py +0 -0
  75. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llm_chat_completion_wrappers/llama3.py +0 -0
  76. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llm_chat_completion_wrappers/simple_summary_wrapper.py +0 -0
  77. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llm_chat_completion_wrappers/wrapper_base.py +0 -0
  78. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/llm_chat_completion_wrappers/zephyr.py +0 -0
  79. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/lmstudio/api.py +0 -0
  80. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/lmstudio/settings.py +0 -0
  81. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/ollama/api.py +0 -0
  82. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/ollama/settings.py +0 -0
  83. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/settings/__init__.py +0 -0
  84. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/settings/deterministic_mirostat.py +0 -0
  85. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/settings/settings.py +0 -0
  86. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/settings/simple.py +0 -0
  87. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/vllm/api.py +0 -0
  88. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/webui/api.py +0 -0
  89. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/webui/legacy_api.py +0 -0
  90. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/webui/legacy_settings.py +0 -0
  91. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/local_llm/webui/settings.py +0 -0
  92. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/log.py +0 -0
  93. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/main.py +0 -0
  94. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/memory.py +0 -0
  95. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/metadata.py +0 -0
  96. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/o1_agent.py +0 -0
  97. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/openai_backcompat/__init__.py +0 -0
  98. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/openai_backcompat/openai_object.py +0 -0
  99. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/__all__.py +0 -0
  100. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/__init__.py +0 -0
  101. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/agents_tags.py +0 -0
  102. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/base.py +0 -0
  103. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/block.py +0 -0
  104. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/blocks_agents.py +0 -0
  105. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/enums.py +0 -0
  106. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/errors.py +0 -0
  107. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/file.py +0 -0
  108. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/mixins.py +0 -0
  109. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/organization.py +0 -0
  110. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/sandbox_config.py +0 -0
  111. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/source.py +0 -0
  112. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/sqlalchemy_base.py +0 -0
  113. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/tool.py +0 -0
  114. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/orm/user.py +0 -0
  115. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/persistence_manager.py +0 -0
  116. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/personas/__init__.py +0 -0
  117. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/personas/examples/anna_pa.txt +0 -0
  118. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/personas/examples/google_search_persona.txt +0 -0
  119. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/personas/examples/memgpt_doc.txt +0 -0
  120. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/personas/examples/memgpt_starter.txt +0 -0
  121. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/personas/examples/o1_persona.txt +0 -0
  122. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/personas/examples/sam.txt +0 -0
  123. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/personas/examples/sam_pov.txt +0 -0
  124. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/personas/examples/sam_simple_pov_gpt35.txt +0 -0
  125. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/personas/examples/sqldb/test.db +0 -0
  126. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/__init__.py +0 -0
  127. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/gpt_summarize.py +0 -0
  128. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/gpt_system.py +0 -0
  129. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/system/memgpt_base.txt +0 -0
  130. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/system/memgpt_chat.txt +0 -0
  131. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/system/memgpt_chat_compressed.txt +0 -0
  132. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/system/memgpt_chat_fstring.txt +0 -0
  133. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/system/memgpt_doc.txt +0 -0
  134. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/system/memgpt_gpt35_extralong.txt +0 -0
  135. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/system/memgpt_intuitive_knowledge.txt +0 -0
  136. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/system/memgpt_modified_chat.txt +0 -0
  137. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/prompts/system/memgpt_modified_o1.txt +0 -0
  138. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/providers.py +0 -0
  139. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/pytest.ini +0 -0
  140. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/agent.py +0 -0
  141. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/agents_tags.py +0 -0
  142. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/api_key.py +0 -0
  143. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/block.py +0 -0
  144. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/blocks_agents.py +0 -0
  145. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/embedding_config.py +0 -0
  146. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/enums.py +0 -0
  147. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/file.py +0 -0
  148. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/health.py +0 -0
  149. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/job.py +0 -0
  150. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/letta_base.py +0 -0
  151. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/letta_message.py +0 -0
  152. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/letta_request.py +0 -0
  153. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/letta_response.py +0 -0
  154. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/llm_config.py +0 -0
  155. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/memory.py +0 -0
  156. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/message.py +0 -0
  157. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/openai/chat_completion_request.py +0 -0
  158. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/openai/chat_completion_response.py +0 -0
  159. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/openai/chat_completions.py +0 -0
  160. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/openai/embedding_response.py +0 -0
  161. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/openai/openai.py +0 -0
  162. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/organization.py +0 -0
  163. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/passage.py +0 -0
  164. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/sandbox_config.py +0 -0
  165. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/source.py +0 -0
  166. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/tool.py +0 -0
  167. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/tool_rule.py +0 -0
  168. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/usage.py +0 -0
  169. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/schemas/user.py +0 -0
  170. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/__init__.py +0 -0
  171. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/constants.py +0 -0
  172. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/generate_openapi_schema.sh +0 -0
  173. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/__init__.py +0 -0
  174. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/auth/__init__.py +0 -0
  175. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/auth/index.py +0 -0
  176. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/auth_token.py +0 -0
  177. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/interface.py +0 -0
  178. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/__init__.py +0 -0
  179. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/openai/__init__.py +0 -0
  180. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/openai/assistants/__init__.py +0 -0
  181. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/openai/assistants/assistants.py +0 -0
  182. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/openai/assistants/schemas.py +0 -0
  183. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/openai/assistants/threads.py +0 -0
  184. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/openai/chat_completions/__init__.py +0 -0
  185. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +0 -0
  186. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/__init__.py +0 -0
  187. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/agents.py +0 -0
  188. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/blocks.py +0 -0
  189. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/health.py +0 -0
  190. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/jobs.py +0 -0
  191. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/llms.py +0 -0
  192. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/organizations.py +0 -0
  193. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/sandbox_configs.py +0 -0
  194. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/sources.py +0 -0
  195. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/tools.py +0 -0
  196. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/routers/v1/users.py +0 -0
  197. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/static_files.py +0 -0
  198. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/rest_api/utils.py +0 -0
  199. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/server.py +0 -0
  200. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/startup.sh +0 -0
  201. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/static_files/assets/index-3ab03d5b.css +0 -0
  202. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/static_files/assets/index-9fa459a2.js +0 -0
  203. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/static_files/favicon.ico +0 -0
  204. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/static_files/index.html +0 -0
  205. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/static_files/memgpt_logo_transparent.png +0 -0
  206. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/utils.py +0 -0
  207. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/ws_api/__init__.py +0 -0
  208. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/ws_api/example_client.py +0 -0
  209. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/ws_api/interface.py +0 -0
  210. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/ws_api/protocol.py +0 -0
  211. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/server/ws_api/server.py +0 -0
  212. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/__init__.py +0 -0
  213. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/agents_tags_manager.py +0 -0
  214. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/block_manager.py +0 -0
  215. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/blocks_agents_manager.py +0 -0
  216. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/organization_manager.py +0 -0
  217. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/per_agent_lock_manager.py +0 -0
  218. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/sandbox_config_manager.py +0 -0
  219. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/source_manager.py +0 -0
  220. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/tool_manager.py +0 -0
  221. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/tool_sandbox_env/.gitkeep +0 -0
  222. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/services/user_manager.py +0 -0
  223. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/settings.py +0 -0
  224. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/streaming_interface.py +0 -0
  225. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/streaming_utils.py +0 -0
  226. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/letta/system.py +0 -0
  227. {letta_nightly-0.5.4.dev20241130104041 → letta_nightly-0.5.4.dev20241201104110}/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.dev20241130104041
3
+ Version: 0.5.4.dev20241201104110
4
4
  Summary: Create LLM agents with long-term memory and custom tools
5
5
  License: Apache License
6
6
  Author: Letta Team
@@ -1,5 +1,6 @@
1
1
  import datetime
2
2
  import inspect
3
+ import time
3
4
  import traceback
4
5
  import warnings
5
6
  from abc import ABC, abstractmethod
@@ -566,60 +567,60 @@ class Agent(BaseAgent):
566
567
  self,
567
568
  message_sequence: List[Message],
568
569
  function_call: str = "auto",
569
- first_message: bool = False, # hint
570
+ first_message: bool = False,
570
571
  stream: bool = False, # TODO move to config?
571
- fail_on_empty_response: bool = False,
572
572
  empty_response_retry_limit: int = 3,
573
+ backoff_factor: float = 0.5, # delay multiplier for exponential backoff
574
+ max_delay: float = 10.0, # max delay between retries
573
575
  ) -> ChatCompletionResponse:
574
- """Get response from LLM API"""
575
- # Get the allowed tools based on the ToolRulesSolver state
576
+ """Get response from LLM API with robust retry mechanism."""
577
+
576
578
  allowed_tool_names = self.tool_rules_solver.get_allowed_tool_names()
579
+ allowed_functions = (
580
+ self.functions if not allowed_tool_names else [func for func in self.functions if func["name"] in allowed_tool_names]
581
+ )
577
582
 
578
- if not allowed_tool_names:
579
- # if it's empty, any available tools are fair game
580
- allowed_functions = self.functions
581
- else:
582
- allowed_functions = [func for func in self.functions if func["name"] in allowed_tool_names]
583
+ for attempt in range(1, empty_response_retry_limit + 1):
584
+ try:
585
+ response = create(
586
+ llm_config=self.agent_state.llm_config,
587
+ messages=message_sequence,
588
+ user_id=self.agent_state.user_id,
589
+ functions=allowed_functions,
590
+ functions_python=self.functions_python,
591
+ function_call=function_call,
592
+ first_message=first_message,
593
+ stream=stream,
594
+ stream_interface=self.interface,
595
+ )
583
596
 
584
- try:
585
- response = create(
586
- # agent_state=self.agent_state,
587
- llm_config=self.agent_state.llm_config,
588
- messages=message_sequence,
589
- user_id=self.agent_state.user_id,
590
- functions=allowed_functions,
591
- functions_python=self.functions_python,
592
- function_call=function_call,
593
- # hint
594
- first_message=first_message,
595
- # streaming
596
- stream=stream,
597
- stream_interface=self.interface,
598
- )
597
+ # These bottom two are retryable
598
+ if len(response.choices) == 0 or response.choices[0] is None:
599
+ raise ValueError(f"API call returned an empty message: {response}")
599
600
 
600
- if len(response.choices) == 0 or response.choices[0] is None:
601
- empty_api_err_message = f"API call didn't return a message: {response}"
602
- if fail_on_empty_response or empty_response_retry_limit == 0:
603
- raise Exception(empty_api_err_message)
604
- else:
605
- # Decrement retry limit and try again
606
- warnings.warn(empty_api_err_message)
607
- return self._get_ai_reply(
608
- message_sequence, function_call, first_message, stream, fail_on_empty_response, empty_response_retry_limit - 1
609
- )
601
+ if response.choices[0].finish_reason not in ["stop", "function_call", "tool_calls"]:
602
+ if response.choices[0].finish_reason == "length":
603
+ # This is not retryable, hence RuntimeError v.s. ValueError
604
+ raise RuntimeError("Finish reason was length (maximum context length)")
605
+ else:
606
+ raise ValueError(f"Bad finish reason from API: {response.choices[0].finish_reason}")
607
+
608
+ return response
610
609
 
611
- # special case for 'length'
612
- if response.choices[0].finish_reason == "length":
613
- raise Exception("Finish reason was length (maximum context length)")
610
+ except ValueError as ve:
611
+ if attempt >= empty_response_retry_limit:
612
+ warnings.warn(f"Retry limit reached. Final error: {ve}")
613
+ break
614
+ else:
615
+ delay = min(backoff_factor * (2 ** (attempt - 1)), max_delay)
616
+ warnings.warn(f"Attempt {attempt} failed: {ve}. Retrying in {delay} seconds...")
617
+ time.sleep(delay)
614
618
 
615
- # catches for soft errors
616
- if response.choices[0].finish_reason not in ["stop", "function_call", "tool_calls"]:
617
- raise Exception(f"API call finish with bad finish reason: {response}")
619
+ except Exception as e:
620
+ # For non-retryable errors, exit immediately
621
+ raise e
618
622
 
619
- # unpack with response.choices[0].message.content
620
- return response
621
- except Exception as e:
622
- raise e
623
+ raise Exception("Retries exhausted and no valid response received.")
623
624
 
624
625
  def _handle_ai_response(
625
626
  self,
@@ -11,23 +11,54 @@ from letta.functions.schema_generator import generate_schema
11
11
 
12
12
 
13
13
  def derive_openai_json_schema(source_code: str, name: Optional[str] = None) -> dict:
14
- # auto-generate openai schema
14
+ """Derives the OpenAI JSON schema for a given function source code.
15
+
16
+ First, attempts to execute the source code in a custom environment with only the necessary imports.
17
+ Then, it generates the schema from the function's docstring and signature.
18
+ """
15
19
  try:
16
20
  # Define a custom environment with necessary imports
17
- env = {"Optional": Optional, "List": List, "Dict": Dict} # Add any other required imports here
18
-
21
+ env = {
22
+ "Optional": Optional,
23
+ "List": List,
24
+ "Dict": Dict,
25
+ # To support Pydantic models
26
+ # "BaseModel": BaseModel,
27
+ # "Field": Field,
28
+ }
19
29
  env.update(globals())
30
+
31
+ # print("About to execute source code...")
20
32
  exec(source_code, env)
33
+ # print("Source code executed successfully")
21
34
 
22
- # get available functions
23
- functions = [f for f in env if callable(env[f])]
35
+ functions = [f for f in env if callable(env[f]) and not f.startswith("__")]
36
+ if not functions:
37
+ raise LettaToolCreateError("No callable functions found in source code")
24
38
 
25
- # TODO: not sure if this always works
39
+ # print(f"Found functions: {functions}")
26
40
  func = env[functions[-1]]
27
- json_schema = generate_schema(func, name=name)
28
- return json_schema
41
+
42
+ if not hasattr(func, "__doc__") or not func.__doc__:
43
+ raise LettaToolCreateError(f"Function {func.__name__} missing docstring")
44
+
45
+ # print("About to generate schema...")
46
+ try:
47
+ schema = generate_schema(func, name=name)
48
+ # print("Schema generated successfully")
49
+ return schema
50
+ except TypeError as e:
51
+ raise LettaToolCreateError(f"Type error in schema generation: {str(e)}")
52
+ except ValueError as e:
53
+ raise LettaToolCreateError(f"Value error in schema generation: {str(e)}")
54
+ except Exception as e:
55
+ raise LettaToolCreateError(f"Unexpected error in schema generation: {str(e)}")
56
+
29
57
  except Exception as e:
30
- raise LettaToolCreateError(f"Failed to derive JSON schema from source code: {e}")
58
+ import traceback
59
+
60
+ traceback.print_exc()
61
+ raise LettaToolCreateError(f"Schema generation failed: {str(e)}") from e
31
62
 
32
63
 
33
64
  def parse_source_code(func) -> str:
@@ -0,0 +1,477 @@
1
+ import inspect
2
+ from typing import Any, Dict, List, Optional, Type, Union, get_args, get_origin
3
+
4
+ from docstring_parser import parse
5
+ from pydantic import BaseModel
6
+ from pydantic.v1 import BaseModel as V1BaseModel
7
+
8
+
9
+ def is_optional(annotation):
10
+ # Check if the annotation is a Union
11
+ if getattr(annotation, "__origin__", None) is Union:
12
+ # Check if None is one of the options in the Union
13
+ return type(None) in annotation.__args__
14
+ return False
15
+
16
+
17
+ def optional_length(annotation):
18
+ if is_optional(annotation):
19
+ # Subtract 1 to account for NoneType
20
+ return len(annotation.__args__) - 1
21
+ else:
22
+ raise ValueError("The annotation is not an Optional type")
23
+
24
+
25
+ def type_to_json_schema_type(py_type) -> dict:
26
+ """
27
+ Maps a Python type to a JSON schema type.
28
+ Specifically handles typing.Optional and common Python types.
29
+ """
30
+ # if get_origin(py_type) is typing.Optional:
31
+ if is_optional(py_type):
32
+ # Assert that Optional has only one type argument
33
+ type_args = get_args(py_type)
34
+ assert optional_length(py_type) == 1, f"Optional type must have exactly one type argument, but got {py_type}"
35
+
36
+ # Extract and map the inner type
37
+ return type_to_json_schema_type(type_args[0])
38
+
39
+ # Handle Union types (except Optional which is handled above)
40
+ if get_origin(py_type) is Union:
41
+ # TODO support mapping Unions to anyOf
42
+ raise NotImplementedError("General Union types are not yet supported")
43
+
44
+ # Handle array types
45
+ origin = get_origin(py_type)
46
+ if py_type == list or origin in (list, List):
47
+ args = get_args(py_type)
48
+
49
+ if args and inspect.isclass(args[0]) and issubclass(args[0], BaseModel):
50
+ # If it's a list of Pydantic models, return an array with the model schema as items
51
+ return {
52
+ "type": "array",
53
+ "items": pydantic_model_to_json_schema(args[0]),
54
+ }
55
+
56
+ # Otherwise, recursively call the basic type checker
57
+ return {
58
+ "type": "array",
59
+ # get the type of the items in the list
60
+ "items": type_to_json_schema_type(args[0]),
61
+ }
62
+
63
+ # Handle object types
64
+ if py_type == dict or origin in (dict, Dict):
65
+ args = get_args(py_type)
66
+ if not args:
67
+ # Generic dict without type arguments
68
+ return {
69
+ "type": "object",
70
+ # "properties": {}
71
+ }
72
+ else:
73
+ raise ValueError(
74
+ f"Dictionary types {py_type} with nested type arguments are not supported (consider using a Pydantic model instead)"
75
+ )
76
+
77
+ # NOTE: the below code works for generic JSON schema parsing, but there's a problem with the key inference
78
+ # when it comes to OpenAI function schema generation so it doesn't make sense to allow for dict[str, Any] type hints
79
+ # key_type, value_type = args
80
+
81
+ # # Ensure dict keys are strings
82
+ # # Otherwise there's no JSON schema equivalent
83
+ # if key_type != str:
84
+ # raise ValueError("Dictionary keys must be strings for OpenAI function schema compatibility")
85
+
86
+ # # Handle value type to determine property schema
87
+ # value_schema = {}
88
+ # if inspect.isclass(value_type) and issubclass(value_type, BaseModel):
89
+ # value_schema = pydantic_model_to_json_schema(value_type)
90
+ # else:
91
+ # value_schema = type_to_json_schema_type(value_type)
92
+
93
+ # # NOTE: the problem lies here - the key is always "key_placeholder"
94
+ # return {"type": "object", "properties": {"key_placeholder": value_schema}}
95
+
96
+ # Handle direct Pydantic models
97
+ if inspect.isclass(py_type) and issubclass(py_type, BaseModel):
98
+ return pydantic_model_to_json_schema(py_type)
99
+
100
+ # Mapping of Python types to JSON schema types
101
+ type_map = {
102
+ # Basic types
103
+ # Optional, Union, and collections are handled above ^
104
+ int: "integer",
105
+ str: "string",
106
+ bool: "boolean",
107
+ float: "number",
108
+ None: "null",
109
+ }
110
+ if py_type not in type_map:
111
+ raise ValueError(f"Python type {py_type} has no corresponding JSON schema type - full map: {type_map}")
112
+ else:
113
+ return {"type": type_map[py_type]}
114
+
115
+
116
+ def pydantic_model_to_open_ai(model: Type[BaseModel]) -> dict:
117
+ """
118
+ Converts a Pydantic model as a singular arg to a JSON schema object for use in OpenAI function calling.
119
+ """
120
+ schema = model.model_json_schema()
121
+ docstring = parse(model.__doc__ or "")
122
+ parameters = {k: v for k, v in schema.items() if k not in ("title", "description")}
123
+ for param in docstring.params:
124
+ if (name := param.arg_name) in parameters["properties"] and (description := param.description):
125
+ if "description" not in parameters["properties"][name]:
126
+ parameters["properties"][name]["description"] = description
127
+
128
+ parameters["required"] = sorted(k for k, v in parameters["properties"].items() if "default" not in v)
129
+
130
+ if "description" not in schema:
131
+ if docstring.short_description:
132
+ schema["description"] = docstring.short_description
133
+ else:
134
+ raise ValueError(f"No description found in docstring or description field (model: {model}, docstring: {docstring})")
135
+
136
+ return {
137
+ "name": schema["title"],
138
+ "description": schema["description"],
139
+ "parameters": parameters,
140
+ }
141
+
142
+
143
+ def pydantic_model_to_json_schema(model: Type[BaseModel]) -> dict:
144
+ """
145
+ Converts a Pydantic model (as an arg that already is annotated) to a JSON schema object for use in OpenAI function calling.
146
+
147
+ An example of a Pydantic model as an arg:
148
+
149
+ class Step(BaseModel):
150
+ name: str = Field(
151
+ ...,
152
+ description="Name of the step.",
153
+ )
154
+ key: str = Field(
155
+ ...,
156
+ description="Unique identifier for the step.",
157
+ )
158
+ description: str = Field(
159
+ ...,
160
+ description="An exhaustic description of what this step is trying to achieve and accomplish.",
161
+ )
162
+
163
+ def create_task_plan(steps: list[Step]):
164
+ '''
165
+ Creates a task plan for the current task.
166
+
167
+ Args:
168
+ steps: List of steps to add to the task plan.
169
+ ...
170
+
171
+ Should result in:
172
+ {
173
+ "name": "create_task_plan",
174
+ "description": "Creates a task plan for the current task.",
175
+ "parameters": {
176
+ "type": "object",
177
+ "properties": {
178
+ "steps": { # <= this is the name of the arg
179
+ "type": "object",
180
+ "description": "List of steps to add to the task plan.",
181
+ "properties": {
182
+ "name": {
183
+ "type": "str",
184
+ "description": "Name of the step.",
185
+ },
186
+ "key": {
187
+ "type": "str",
188
+ "description": "Unique identifier for the step.",
189
+ },
190
+ "description": {
191
+ "type": "str",
192
+ "description": "An exhaustic description of what this step is trying to achieve and accomplish.",
193
+ },
194
+ },
195
+ "required": ["name", "key", "description"],
196
+ }
197
+ },
198
+ "required": ["steps"],
199
+ }
200
+ }
201
+
202
+ Specifically, the result of pydantic_model_to_json_schema(steps) (where `steps` is an instance of BaseModel) is:
203
+ {
204
+ "type": "object",
205
+ "properties": {
206
+ "name": {
207
+ "type": "str",
208
+ "description": "Name of the step."
209
+ },
210
+ "key": {
211
+ "type": "str",
212
+ "description": "Unique identifier for the step."
213
+ },
214
+ "description": {
215
+ "type": "str",
216
+ "description": "An exhaustic description of what this step is trying to achieve and accomplish."
217
+ },
218
+ },
219
+ "required": ["name", "key", "description"],
220
+ }
221
+ """
222
+ schema = model.model_json_schema()
223
+
224
+ def clean_property(prop: dict) -> dict:
225
+ """Clean up a property schema to match desired format"""
226
+
227
+ if "description" not in prop:
228
+ raise ValueError(f"Property {prop} lacks a 'description' key")
229
+
230
+ return {
231
+ "type": "string" if prop["type"] == "string" else prop["type"],
232
+ "description": prop["description"],
233
+ }
234
+
235
+ def resolve_ref(ref: str, schema: dict) -> dict:
236
+ """Resolve a $ref reference in the schema"""
237
+ if not ref.startswith("#/$defs/"):
238
+ raise ValueError(f"Unexpected reference format: {ref}")
239
+
240
+ model_name = ref.split("/")[-1]
241
+ if model_name not in schema.get("$defs", {}):
242
+ raise ValueError(f"Reference {model_name} not found in schema definitions")
243
+
244
+ return schema["$defs"][model_name]
245
+
246
+ def clean_schema(schema_part: dict, full_schema: dict) -> dict:
247
+ """Clean up a schema part, handling references and nested structures"""
248
+ # Handle $ref
249
+ if "$ref" in schema_part:
250
+ schema_part = resolve_ref(schema_part["$ref"], full_schema)
251
+
252
+ if "type" not in schema_part:
253
+ raise ValueError(f"Schema part lacks a 'type' key: {schema_part}")
254
+
255
+ # Handle array type
256
+ if schema_part["type"] == "array":
257
+ items_schema = schema_part["items"]
258
+ if "$ref" in items_schema:
259
+ items_schema = resolve_ref(items_schema["$ref"], full_schema)
260
+ return {"type": "array", "items": clean_schema(items_schema, full_schema), "description": schema_part.get("description", "")}
261
+
262
+ # Handle object type
263
+ if schema_part["type"] == "object":
264
+ if "properties" not in schema_part:
265
+ raise ValueError(f"Object schema lacks 'properties' key: {schema_part}")
266
+
267
+ properties = {}
268
+ for name, prop in schema_part["properties"].items():
269
+ if "items" in prop: # Handle arrays
270
+ if "description" not in prop:
271
+ raise ValueError(f"Property {prop} lacks a 'description' key")
272
+ properties[name] = {
273
+ "type": "array",
274
+ "items": clean_schema(prop["items"], full_schema),
275
+ "description": prop["description"],
276
+ }
277
+ else:
278
+ properties[name] = clean_property(prop)
279
+
280
+ pydantic_model_schema_dict = {
281
+ "type": "object",
282
+ "properties": properties,
283
+ "required": schema_part.get("required", []),
284
+ }
285
+ if "description" in schema_part:
286
+ pydantic_model_schema_dict["description"] = schema_part["description"]
287
+
288
+ return pydantic_model_schema_dict
289
+
290
+ # Handle primitive types
291
+ return clean_property(schema_part)
292
+
293
+ return clean_schema(schema_part=schema, full_schema=schema)
294
+
295
+
296
+ def generate_schema(function, name: Optional[str] = None, description: Optional[str] = None) -> dict:
297
+ # Get the signature of the function
298
+ sig = inspect.signature(function)
299
+
300
+ # Parse the docstring
301
+ docstring = parse(function.__doc__)
302
+
303
+ # Prepare the schema dictionary
304
+ schema = {
305
+ "name": function.__name__ if name is None else name,
306
+ "description": docstring.short_description if description is None else description,
307
+ "parameters": {"type": "object", "properties": {}, "required": []},
308
+ }
309
+
310
+ # TODO: ensure that 'agent' keyword is reserved for `Agent` class
311
+
312
+ for param in sig.parameters.values():
313
+ # Exclude 'self' parameter
314
+ # TODO: eventually remove this (only applies to BASE_TOOLS)
315
+ if param.name == "self":
316
+ continue
317
+
318
+ # exclude 'agent_state' parameter
319
+ if param.name == "agent_state":
320
+ continue
321
+
322
+ # Assert that the parameter has a type annotation
323
+ if param.annotation == inspect.Parameter.empty:
324
+ raise TypeError(f"Parameter '{param.name}' in function '{function.__name__}' lacks a type annotation")
325
+
326
+ # Find the parameter's description in the docstring
327
+ param_doc = next((d for d in docstring.params if d.arg_name == param.name), None)
328
+
329
+ # Assert that the parameter has a description
330
+ if not param_doc or not param_doc.description:
331
+ raise ValueError(f"Parameter '{param.name}' in function '{function.__name__}' lacks a description in the docstring")
332
+
333
+ # If the parameter is a pydantic model, we need to unpack the Pydantic model type into a JSON schema object
334
+ # if inspect.isclass(param.annotation) and issubclass(param.annotation, BaseModel):
335
+ if (
336
+ (inspect.isclass(param.annotation) or inspect.isclass(get_origin(param.annotation) or param.annotation))
337
+ and not get_origin(param.annotation)
338
+ and issubclass(param.annotation, BaseModel)
339
+ ):
340
+ # print("Generating schema for pydantic model:", param.annotation)
341
+ # Extract the properties from the pydantic model
342
+ schema["parameters"]["properties"][param.name] = pydantic_model_to_json_schema(param.annotation)
343
+ schema["parameters"]["properties"][param.name]["description"] = param_doc.description
344
+
345
+ # Otherwise, we convert the Python typing to JSON schema types
346
+ # NOTE: important - if a dict or list, the internal type can be a Pydantic model itself
347
+ # however in that
348
+ else:
349
+ # print("Generating schema for non-pydantic model:", param.annotation)
350
+ # Grab the description for the parameter from the extended docstring
351
+ # If it doesn't exist, we should raise an error
352
+ param_doc = next((d for d in docstring.params if d.arg_name == param.name), None)
353
+ if not param_doc:
354
+ raise ValueError(f"Parameter '{param.name}' in function '{function.__name__}' lacks a description in the docstring")
355
+ elif not isinstance(param_doc.description, str):
356
+ raise ValueError(
357
+ f"Parameter '{param.name}' in function '{function.__name__}' has a description in the docstring that is not a string (type: {type(param_doc.description)})"
358
+ )
359
+ else:
360
+ # If it's a string or a basic type, then all you need is: (1) type, (2) description
361
+ # If it's a more complex type, then you also need either:
362
+ # - for array, you need "items", each of which has "type"
363
+ # - for a dict, you need "properties", which has keys which each have "type"
364
+ if param.annotation != inspect.Parameter.empty:
365
+ param_generated_schema = type_to_json_schema_type(param.annotation)
366
+ else:
367
+ # TODO why are we inferring here?
368
+ param_generated_schema = {"type": "string"}
369
+
370
+ # Add in the description
371
+ param_generated_schema["description"] = param_doc.description
372
+
373
+ # Add the schema to the function arg key
374
+ schema["parameters"]["properties"][param.name] = param_generated_schema
375
+
376
+ # If the parameter doesn't have a default value, it is required (so we need to add it to the required list)
377
+ if param.default == inspect.Parameter.empty and not is_optional(param.annotation):
378
+ schema["parameters"]["required"].append(param.name)
379
+
380
+ # TODO what's going on here?
381
+ # If the parameter is a list of strings we need to hard cast to "string" instead of `str`
382
+ if get_origin(param.annotation) is list:
383
+ if get_args(param.annotation)[0] is str:
384
+ schema["parameters"]["properties"][param.name]["items"] = {"type": "string"}
385
+
386
+ # TODO is this not duplicating the other append directly above?
387
+ if param.annotation == inspect.Parameter.empty:
388
+ schema["parameters"]["required"].append(param.name)
389
+
390
+ # append the heartbeat
391
+ # TODO: don't hard-code
392
+ # TODO: if terminal, don't include this
393
+ if function.__name__ not in ["send_message", "pause_heartbeats"]:
394
+ schema["parameters"]["properties"]["request_heartbeat"] = {
395
+ "type": "boolean",
396
+ "description": "Request an immediate heartbeat after function execution. Set to `True` if you want to send a follow-up message or run a follow-up function.",
397
+ }
398
+ schema["parameters"]["required"].append("request_heartbeat")
399
+
400
+ return schema
401
+
402
+
403
+ def generate_schema_from_args_schema_v1(
404
+ args_schema: Type[V1BaseModel], name: Optional[str] = None, description: Optional[str] = None, append_heartbeat: bool = True
405
+ ) -> Dict[str, Any]:
406
+ properties = {}
407
+ required = []
408
+ for field_name, field in args_schema.__fields__.items():
409
+ if field.type_ == str:
410
+ field_type = "string"
411
+ elif field.type_ == int:
412
+ field_type = "integer"
413
+ elif field.type_ == bool:
414
+ field_type = "boolean"
415
+ else:
416
+ field_type = field.type_.__name__
417
+
418
+ properties[field_name] = {
419
+ "type": field_type,
420
+ "description": field.field_info.description,
421
+ }
422
+ if field.required:
423
+ required.append(field_name)
424
+
425
+ function_call_json = {
426
+ "name": name,
427
+ "description": description,
428
+ "parameters": {"type": "object", "properties": properties, "required": required},
429
+ }
430
+
431
+ if append_heartbeat:
432
+ function_call_json["parameters"]["properties"]["request_heartbeat"] = {
433
+ "type": "boolean",
434
+ "description": "Request an immediate heartbeat after function execution. Set to `True` if you want to send a follow-up message or run a follow-up function.",
435
+ }
436
+ function_call_json["parameters"]["required"].append("request_heartbeat")
437
+
438
+ return function_call_json
439
+
440
+
441
+ def generate_schema_from_args_schema_v2(
442
+ args_schema: Type[BaseModel], name: Optional[str] = None, description: Optional[str] = None, append_heartbeat: bool = True
443
+ ) -> Dict[str, Any]:
444
+ properties = {}
445
+ required = []
446
+ for field_name, field in args_schema.model_fields.items():
447
+ field_type_annotation = field.annotation
448
+ if field_type_annotation == str:
449
+ field_type = "string"
450
+ elif field_type_annotation == int:
451
+ field_type = "integer"
452
+ elif field_type_annotation == bool:
453
+ field_type = "boolean"
454
+ else:
455
+ field_type = field_type_annotation.__name__
456
+
457
+ properties[field_name] = {
458
+ "type": field_type,
459
+ "description": field.description,
460
+ }
461
+ if field.is_required():
462
+ required.append(field_name)
463
+
464
+ function_call_json = {
465
+ "name": name,
466
+ "description": description,
467
+ "parameters": {"type": "object", "properties": properties, "required": required},
468
+ }
469
+
470
+ if append_heartbeat:
471
+ function_call_json["parameters"]["properties"]["request_heartbeat"] = {
472
+ "type": "boolean",
473
+ "description": "Request an immediate heartbeat after function execution. Set to `True` if you want to send a follow-up message or run a follow-up function.",
474
+ }
475
+ function_call_json["parameters"]["required"].append("request_heartbeat")
476
+
477
+ return function_call_json