letta-nightly 0.5.1.dev20241105104128__tar.gz → 0.5.2.dev20241107104040__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.
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/PKG-INFO +5 -2
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/README.md +4 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/__init__.py +1 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/agent.py +14 -4
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/agent_store/db.py +22 -20
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/cli/cli.py +14 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/client/client.py +27 -14
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/constants.py +3 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/functions/functions.py +1 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/helpers/tool_rule_solver.py +1 -2
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/log.py +1 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/main.py +3 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/metadata.py +2 -0
- letta_nightly-0.5.2.dev20241107104040/letta/orm/agents_tags.py +28 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/base.py +5 -2
- letta_nightly-0.5.2.dev20241107104040/letta/orm/mixins.py +31 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/organization.py +4 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/sqlalchemy_base.py +22 -45
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/tool.py +3 -2
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/user.py +3 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/agent.py +5 -0
- letta_nightly-0.5.2.dev20241107104040/letta/schemas/agents_tags.py +33 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/block.py +3 -3
- letta_nightly-0.5.2.dev20241107104040/letta/schemas/letta_response.py +149 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/llm_config.py +7 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/memory.py +4 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/organization.py +4 -4
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/tool.py +13 -9
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/tool_rule.py +12 -2
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/user.py +1 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/app.py +4 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/v1/agents.py +7 -122
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/v1/organizations.py +2 -1
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/v1/tools.py +3 -2
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/v1/users.py +14 -2
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/server.py +75 -44
- letta_nightly-0.5.2.dev20241107104040/letta/services/agents_tags_manager.py +64 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/services/organization_manager.py +4 -4
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/services/tool_manager.py +22 -30
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/services/user_manager.py +3 -3
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/pyproject.toml +1 -1
- letta_nightly-0.5.1.dev20241105104128/letta/orm/mixins.py +0 -82
- letta_nightly-0.5.1.dev20241105104128/letta/schemas/letta_response.py +0 -39
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/LICENSE +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/__main__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/agent_store/chroma.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/agent_store/lancedb.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/agent_store/milvus.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/agent_store/qdrant.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/agent_store/storage.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/benchmark/benchmark.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/benchmark/constants.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/cli/cli_config.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/cli/cli_load.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/client/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/client/streaming.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/client/utils.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/config.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/credentials.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/data_sources/connectors.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/data_sources/connectors_helper.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/embeddings.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/errors.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/functions/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/functions/function_sets/base.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/functions/function_sets/extras.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/functions/helpers.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/functions/schema_generator.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/helpers/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/humans/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/humans/examples/basic.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/humans/examples/cs_phd.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/interface.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/llm_api/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/llm_api/anthropic.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/llm_api/azure_openai.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/llm_api/azure_openai_constants.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/llm_api/cohere.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/llm_api/google_ai.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/llm_api/helpers.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/llm_api/llm_api_tools.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/llm_api/mistral.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/llm_api/openai.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/README.md +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/chat_completion_proxy.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/constants.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/function_parser.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/grammars/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/grammars/gbnf_grammar_generator.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/grammars/json.gbnf +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/grammars/json_func_calls_with_inner_thoughts.gbnf +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/json_parser.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/koboldcpp/api.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/koboldcpp/settings.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llamacpp/api.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llamacpp/settings.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llm_chat_completion_wrappers/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llm_chat_completion_wrappers/airoboros.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llm_chat_completion_wrappers/chatml.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llm_chat_completion_wrappers/dolphin.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llm_chat_completion_wrappers/llama3.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llm_chat_completion_wrappers/simple_summary_wrapper.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llm_chat_completion_wrappers/wrapper_base.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/llm_chat_completion_wrappers/zephyr.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/lmstudio/api.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/lmstudio/settings.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/ollama/api.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/ollama/settings.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/settings/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/settings/deterministic_mirostat.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/settings/settings.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/settings/simple.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/utils.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/vllm/api.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/webui/api.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/webui/legacy_api.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/webui/legacy_settings.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/local_llm/webui/settings.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/memory.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/o1_agent.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/openai_backcompat/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/openai_backcompat/openai_object.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/__all__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/enums.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/errors.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/persistence_manager.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/personas/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/personas/examples/anna_pa.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/personas/examples/google_search_persona.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/personas/examples/memgpt_doc.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/personas/examples/memgpt_starter.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/personas/examples/o1_persona.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/personas/examples/sam.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/personas/examples/sam_pov.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/personas/examples/sam_simple_pov_gpt35.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/personas/examples/sqldb/test.db +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/gpt_summarize.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/gpt_system.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/system/memgpt_base.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/system/memgpt_chat.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/system/memgpt_chat_compressed.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/system/memgpt_chat_fstring.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/system/memgpt_doc.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/system/memgpt_gpt35_extralong.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/system/memgpt_intuitive_knowledge.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/system/memgpt_modified_chat.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/prompts/system/memgpt_modified_o1.txt +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/providers.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/pytest.ini +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/api_key.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/embedding_config.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/enums.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/file.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/health.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/job.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/letta_base.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/letta_message.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/letta_request.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/message.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/openai/chat_completion_request.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/openai/chat_completion_response.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/openai/chat_completions.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/openai/embedding_response.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/openai/openai.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/passage.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/source.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/schemas/usage.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/constants.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/auth/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/auth/index.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/auth_token.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/interface.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/openai/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/openai/assistants/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/openai/assistants/assistants.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/openai/assistants/schemas.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/openai/assistants/threads.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/openai/chat_completions/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/v1/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/v1/blocks.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/v1/health.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/v1/jobs.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/v1/llms.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/routers/v1/sources.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/static_files.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/rest_api/utils.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/startup.sh +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/static_files/assets/index-3ab03d5b.css +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/static_files/assets/index-9fa459a2.js +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/static_files/favicon.ico +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/static_files/index.html +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/static_files/memgpt_logo_transparent.png +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/utils.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/ws_api/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/ws_api/example_client.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/ws_api/interface.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/ws_api/protocol.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/server/ws_api/server.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/services/__init__.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/settings.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/streaming_interface.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/streaming_utils.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/system.py +0 -0
- {letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: letta-nightly
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2.dev20241107104040
|
|
4
4
|
Summary: Create LLM agents with long-term memory and custom tools
|
|
5
5
|
License: Apache License
|
|
6
6
|
Author: Letta Team
|
|
@@ -99,14 +99,17 @@ Description-Content-Type: text/markdown
|
|
|
99
99
|
</h3>
|
|
100
100
|
|
|
101
101
|
**👾 Letta** is an open source framework for building stateful LLM applications. You can use Letta to build **stateful agents** with advanced reasoning capabilities and transparent long-term memory. The Letta framework is white box and model-agnostic.
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
[](https://discord.gg/letta)
|
|
104
104
|
[](https://twitter.com/Letta_AI)
|
|
105
105
|
[](https://arxiv.org/abs/2310.08560)
|
|
106
|
+
|
|
106
107
|
[](LICENSE)
|
|
107
108
|
[](https://github.com/cpacker/MemGPT/releases)
|
|
108
109
|
[](https://github.com/cpacker/MemGPT)
|
|
109
110
|
|
|
111
|
+
<a href="https://trendshift.io/repositories/3612" target="_blank"><img src="https://trendshift.io/api/badge/repositories/3612" alt="cpacker%2FMemGPT | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
|
112
|
+
|
|
110
113
|
</div>
|
|
111
114
|
|
|
112
115
|
> [!NOTE]
|
|
@@ -16,14 +16,17 @@
|
|
|
16
16
|
</h3>
|
|
17
17
|
|
|
18
18
|
**👾 Letta** is an open source framework for building stateful LLM applications. You can use Letta to build **stateful agents** with advanced reasoning capabilities and transparent long-term memory. The Letta framework is white box and model-agnostic.
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
[](https://discord.gg/letta)
|
|
21
21
|
[](https://twitter.com/Letta_AI)
|
|
22
22
|
[](https://arxiv.org/abs/2310.08560)
|
|
23
|
+
|
|
23
24
|
[](LICENSE)
|
|
24
25
|
[](https://github.com/cpacker/MemGPT/releases)
|
|
25
26
|
[](https://github.com/cpacker/MemGPT)
|
|
26
27
|
|
|
28
|
+
<a href="https://trendshift.io/repositories/3612" target="_blank"><img src="https://trendshift.io/api/badge/repositories/3612" alt="cpacker%2FMemGPT | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
|
29
|
+
|
|
27
30
|
</div>
|
|
28
31
|
|
|
29
32
|
> [!NOTE]
|
{letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/agent.py
RENAMED
|
@@ -248,9 +248,21 @@ class Agent(BaseAgent):
|
|
|
248
248
|
# initialize a tool rules solver
|
|
249
249
|
if agent_state.tool_rules:
|
|
250
250
|
# if there are tool rules, print out a warning
|
|
251
|
-
|
|
251
|
+
for rule in agent_state.tool_rules:
|
|
252
|
+
if not isinstance(rule, TerminalToolRule):
|
|
253
|
+
warnings.warn("Tool rules only work reliably for the latest OpenAI models that support structured outputs.")
|
|
254
|
+
break
|
|
252
255
|
# add default rule for having send_message be a terminal tool
|
|
253
|
-
agent_state.tool_rules
|
|
256
|
+
if agent_state.tool_rules is None:
|
|
257
|
+
agent_state.tool_rules = []
|
|
258
|
+
# Define the rule to add
|
|
259
|
+
send_message_terminal_rule = TerminalToolRule(tool_name="send_message")
|
|
260
|
+
# Check if an equivalent rule is already present
|
|
261
|
+
if not any(
|
|
262
|
+
isinstance(rule, TerminalToolRule) and rule.tool_name == send_message_terminal_rule.tool_name for rule in agent_state.tool_rules
|
|
263
|
+
):
|
|
264
|
+
agent_state.tool_rules.append(send_message_terminal_rule)
|
|
265
|
+
|
|
254
266
|
self.tool_rules_solver = ToolRulesSolver(tool_rules=agent_state.tool_rules)
|
|
255
267
|
|
|
256
268
|
# gpt-4, gpt-3.5-turbo, ...
|
|
@@ -392,7 +404,6 @@ class Agent(BaseAgent):
|
|
|
392
404
|
exec(tool.module, env)
|
|
393
405
|
else:
|
|
394
406
|
exec(tool.source_code, env)
|
|
395
|
-
|
|
396
407
|
self.functions_python[tool.json_schema["name"]] = env[tool.json_schema["name"]]
|
|
397
408
|
self.functions.append(tool.json_schema)
|
|
398
409
|
except Exception as e:
|
|
@@ -784,7 +795,6 @@ class Agent(BaseAgent):
|
|
|
784
795
|
|
|
785
796
|
# Update ToolRulesSolver state with last called function
|
|
786
797
|
self.tool_rules_solver.update_tool_usage(function_name)
|
|
787
|
-
|
|
788
798
|
# Update heartbeat request according to provided tool rules
|
|
789
799
|
if self.tool_rules_solver.has_children_tools(function_name):
|
|
790
800
|
heartbeat_request = True
|
|
@@ -358,26 +358,26 @@ class PostgresStorageConnector(SQLStorageConnector):
|
|
|
358
358
|
# construct URI from enviornment variables
|
|
359
359
|
if settings.pg_uri:
|
|
360
360
|
self.uri = settings.pg_uri
|
|
361
|
+
|
|
362
|
+
# use config URI
|
|
363
|
+
# TODO: remove this eventually (config should NOT contain URI)
|
|
364
|
+
if table_type == TableType.ARCHIVAL_MEMORY or table_type == TableType.PASSAGES:
|
|
365
|
+
self.uri = self.config.archival_storage_uri
|
|
366
|
+
self.db_model = PassageModel
|
|
367
|
+
if self.config.archival_storage_uri is None:
|
|
368
|
+
raise ValueError(f"Must specify archival_storage_uri in config {self.config.config_path}")
|
|
369
|
+
elif table_type == TableType.RECALL_MEMORY:
|
|
370
|
+
self.uri = self.config.recall_storage_uri
|
|
371
|
+
self.db_model = MessageModel
|
|
372
|
+
if self.config.recall_storage_uri is None:
|
|
373
|
+
raise ValueError(f"Must specify recall_storage_uri in config {self.config.config_path}")
|
|
374
|
+
elif table_type == TableType.FILES:
|
|
375
|
+
self.uri = self.config.metadata_storage_uri
|
|
376
|
+
self.db_model = FileMetadataModel
|
|
377
|
+
if self.config.metadata_storage_uri is None:
|
|
378
|
+
raise ValueError(f"Must specify metadata_storage_uri in config {self.config.config_path}")
|
|
361
379
|
else:
|
|
362
|
-
|
|
363
|
-
# TODO: remove this eventually (config should NOT contain URI)
|
|
364
|
-
if table_type == TableType.ARCHIVAL_MEMORY or table_type == TableType.PASSAGES:
|
|
365
|
-
self.uri = self.config.archival_storage_uri
|
|
366
|
-
self.db_model = PassageModel
|
|
367
|
-
if self.config.archival_storage_uri is None:
|
|
368
|
-
raise ValueError(f"Must specify archival_storage_uri in config {self.config.config_path}")
|
|
369
|
-
elif table_type == TableType.RECALL_MEMORY:
|
|
370
|
-
self.uri = self.config.recall_storage_uri
|
|
371
|
-
self.db_model = MessageModel
|
|
372
|
-
if self.config.recall_storage_uri is None:
|
|
373
|
-
raise ValueError(f"Must specify recall_storage_uri in config {self.config.config_path}")
|
|
374
|
-
elif table_type == TableType.FILES:
|
|
375
|
-
self.uri = self.config.metadata_storage_uri
|
|
376
|
-
self.db_model = FileMetadataModel
|
|
377
|
-
if self.config.metadata_storage_uri is None:
|
|
378
|
-
raise ValueError(f"Must specify metadata_storage_uri in config {self.config.config_path}")
|
|
379
|
-
else:
|
|
380
|
-
raise ValueError(f"Table type {table_type} not implemented")
|
|
380
|
+
raise ValueError(f"Table type {table_type} not implemented")
|
|
381
381
|
|
|
382
382
|
for c in self.db_model.__table__.columns:
|
|
383
383
|
if c.name == "embedding":
|
|
@@ -578,4 +578,6 @@ class SQLLiteStorageConnector(SQLStorageConnector):
|
|
|
578
578
|
def attach_base():
|
|
579
579
|
# This should be invoked in server.py to make sure Base gets initialized properly
|
|
580
580
|
# DO NOT REMOVE
|
|
581
|
-
|
|
581
|
+
from letta.utils import printd
|
|
582
|
+
|
|
583
|
+
printd("Initializing database...")
|
{letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/cli/cli.py
RENAMED
|
@@ -10,7 +10,7 @@ import letta.utils as utils
|
|
|
10
10
|
from letta import create_client
|
|
11
11
|
from letta.agent import Agent, save_agent
|
|
12
12
|
from letta.config import LettaConfig
|
|
13
|
-
from letta.constants import CLI_WARNING_PREFIX, LETTA_DIR
|
|
13
|
+
from letta.constants import CLI_WARNING_PREFIX, LETTA_DIR, MIN_CONTEXT_WINDOW
|
|
14
14
|
from letta.local_llm.constants import ASSISTANT_MESSAGE_CLI_SYMBOL
|
|
15
15
|
from letta.log import get_logger
|
|
16
16
|
from letta.metadata import MetadataStore
|
|
@@ -244,6 +244,19 @@ def run(
|
|
|
244
244
|
llm_model_name = questionary.select("Select LLM model:", choices=llm_choices).ask().model
|
|
245
245
|
llm_config = [llm_config for llm_config in llm_configs if llm_config.model == llm_model_name][0]
|
|
246
246
|
|
|
247
|
+
# option to override context window
|
|
248
|
+
if llm_config.context_window is not None:
|
|
249
|
+
context_window_validator = lambda x: x.isdigit() and int(x) > MIN_CONTEXT_WINDOW and int(x) <= llm_config.context_window
|
|
250
|
+
context_window_input = questionary.text(
|
|
251
|
+
"Select LLM context window limit (hit enter for default):",
|
|
252
|
+
default=str(llm_config.context_window),
|
|
253
|
+
validate=context_window_validator,
|
|
254
|
+
).ask()
|
|
255
|
+
if context_window_input is not None:
|
|
256
|
+
llm_config.context_window = int(context_window_input)
|
|
257
|
+
else:
|
|
258
|
+
sys.exit(1)
|
|
259
|
+
|
|
247
260
|
# choose form list of embedding configs
|
|
248
261
|
embedding_configs = client.list_embedding_configs()
|
|
249
262
|
embedding_options = [embedding_config.embedding_model for embedding_config in embedding_configs]
|
|
@@ -77,6 +77,7 @@ class AbstractClient(object):
|
|
|
77
77
|
memory: Memory = ChatMemory(human=get_human_text(DEFAULT_HUMAN), persona=get_persona_text(DEFAULT_PERSONA)),
|
|
78
78
|
system: Optional[str] = None,
|
|
79
79
|
tools: Optional[List[str]] = None,
|
|
80
|
+
tool_rules: Optional[List[BaseToolRule]] = None,
|
|
80
81
|
include_base_tools: Optional[bool] = True,
|
|
81
82
|
metadata: Optional[Dict] = {"human:": DEFAULT_HUMAN, "persona": DEFAULT_PERSONA},
|
|
82
83
|
description: Optional[str] = None,
|
|
@@ -333,8 +334,12 @@ class RESTClient(AbstractClient):
|
|
|
333
334
|
self._default_llm_config = default_llm_config
|
|
334
335
|
self._default_embedding_config = default_embedding_config
|
|
335
336
|
|
|
336
|
-
def list_agents(self) -> List[AgentState]:
|
|
337
|
-
|
|
337
|
+
def list_agents(self, tags: Optional[List[str]] = None) -> List[AgentState]:
|
|
338
|
+
params = {}
|
|
339
|
+
if tags:
|
|
340
|
+
params["tags"] = tags
|
|
341
|
+
|
|
342
|
+
response = requests.get(f"{self.base_url}/{self.api_prefix}/agents", headers=self.headers, params=params)
|
|
338
343
|
return [AgentState(**agent) for agent in response.json()]
|
|
339
344
|
|
|
340
345
|
def agent_exists(self, agent_id: str) -> bool:
|
|
@@ -372,6 +377,7 @@ class RESTClient(AbstractClient):
|
|
|
372
377
|
system: Optional[str] = None,
|
|
373
378
|
# tools
|
|
374
379
|
tools: Optional[List[str]] = None,
|
|
380
|
+
tool_rules: Optional[List[BaseToolRule]] = None,
|
|
375
381
|
include_base_tools: Optional[bool] = True,
|
|
376
382
|
# metadata
|
|
377
383
|
metadata: Optional[Dict] = {"human:": DEFAULT_HUMAN, "persona": DEFAULT_PERSONA},
|
|
@@ -425,6 +431,7 @@ class RESTClient(AbstractClient):
|
|
|
425
431
|
metadata_=metadata,
|
|
426
432
|
memory=memory,
|
|
427
433
|
tools=tool_names,
|
|
434
|
+
tool_rules=tool_rules,
|
|
428
435
|
system=system,
|
|
429
436
|
agent_type=agent_type,
|
|
430
437
|
llm_config=llm_config if llm_config else self._default_llm_config,
|
|
@@ -477,6 +484,7 @@ class RESTClient(AbstractClient):
|
|
|
477
484
|
description: Optional[str] = None,
|
|
478
485
|
system: Optional[str] = None,
|
|
479
486
|
tools: Optional[List[str]] = None,
|
|
487
|
+
tags: Optional[List[str]] = None,
|
|
480
488
|
metadata: Optional[Dict] = None,
|
|
481
489
|
llm_config: Optional[LLMConfig] = None,
|
|
482
490
|
embedding_config: Optional[EmbeddingConfig] = None,
|
|
@@ -506,6 +514,7 @@ class RESTClient(AbstractClient):
|
|
|
506
514
|
name=name,
|
|
507
515
|
system=system,
|
|
508
516
|
tools=tools,
|
|
517
|
+
tags=tags,
|
|
509
518
|
description=description,
|
|
510
519
|
metadata_=metadata,
|
|
511
520
|
llm_config=llm_config,
|
|
@@ -612,7 +621,12 @@ class RESTClient(AbstractClient):
|
|
|
612
621
|
agent_id (str): ID of the agent
|
|
613
622
|
"""
|
|
614
623
|
# TODO: implement this
|
|
615
|
-
|
|
624
|
+
response = requests.get(f"{self.base_url}/{self.api_prefix}/agents", headers=self.headers, params={"name": agent_name})
|
|
625
|
+
agents = [AgentState(**agent) for agent in response.json()]
|
|
626
|
+
if len(agents) == 0:
|
|
627
|
+
return None
|
|
628
|
+
assert len(agents) == 1, f"Multiple agents with the same name: {agents}"
|
|
629
|
+
return agents[0].id
|
|
616
630
|
|
|
617
631
|
# memory
|
|
618
632
|
def get_in_context_memory(self, agent_id: str) -> Memory:
|
|
@@ -1609,13 +1623,10 @@ class LocalClient(AbstractClient):
|
|
|
1609
1623
|
self.organization = self.server.get_organization_or_default(self.org_id)
|
|
1610
1624
|
|
|
1611
1625
|
# agents
|
|
1612
|
-
def list_agents(self) -> List[AgentState]:
|
|
1626
|
+
def list_agents(self, tags: Optional[List[str]] = None) -> List[AgentState]:
|
|
1613
1627
|
self.interface.clear()
|
|
1614
1628
|
|
|
1615
|
-
|
|
1616
|
-
# return self.server.list_agents(user_id=self.user_id)
|
|
1617
|
-
|
|
1618
|
-
return self.server.ms.list_agents(user_id=self.user_id)
|
|
1629
|
+
return self.server.list_agents(user_id=self.user_id, tags=tags)
|
|
1619
1630
|
|
|
1620
1631
|
def agent_exists(self, agent_id: Optional[str] = None, agent_name: Optional[str] = None) -> bool:
|
|
1621
1632
|
"""
|
|
@@ -1749,6 +1760,7 @@ class LocalClient(AbstractClient):
|
|
|
1749
1760
|
description: Optional[str] = None,
|
|
1750
1761
|
system: Optional[str] = None,
|
|
1751
1762
|
tools: Optional[List[str]] = None,
|
|
1763
|
+
tags: Optional[List[str]] = None,
|
|
1752
1764
|
metadata: Optional[Dict] = None,
|
|
1753
1765
|
llm_config: Optional[LLMConfig] = None,
|
|
1754
1766
|
embedding_config: Optional[EmbeddingConfig] = None,
|
|
@@ -1780,6 +1792,7 @@ class LocalClient(AbstractClient):
|
|
|
1780
1792
|
name=name,
|
|
1781
1793
|
system=system,
|
|
1782
1794
|
tools=tools,
|
|
1795
|
+
tags=tags,
|
|
1783
1796
|
description=description,
|
|
1784
1797
|
metadata_=metadata,
|
|
1785
1798
|
llm_config=llm_config,
|
|
@@ -1864,7 +1877,7 @@ class LocalClient(AbstractClient):
|
|
|
1864
1877
|
agent_state (AgentState): State of the agent
|
|
1865
1878
|
"""
|
|
1866
1879
|
self.interface.clear()
|
|
1867
|
-
return self.server.
|
|
1880
|
+
return self.server.get_agent_state(agent_name=agent_name, user_id=self.user_id, agent_id=None)
|
|
1868
1881
|
|
|
1869
1882
|
def get_agent(self, agent_id: str) -> AgentState:
|
|
1870
1883
|
"""
|
|
@@ -2267,18 +2280,18 @@ class LocalClient(AbstractClient):
|
|
|
2267
2280
|
langchain_tool=langchain_tool,
|
|
2268
2281
|
additional_imports_module_attr_map=additional_imports_module_attr_map,
|
|
2269
2282
|
)
|
|
2270
|
-
return self.server.tool_manager.create_or_update_tool(tool_create, actor=self.user)
|
|
2283
|
+
return self.server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=self.user)
|
|
2271
2284
|
|
|
2272
2285
|
def load_crewai_tool(self, crewai_tool: "CrewAIBaseTool", additional_imports_module_attr_map: dict[str, str] = None) -> Tool:
|
|
2273
2286
|
tool_create = ToolCreate.from_crewai(
|
|
2274
2287
|
crewai_tool=crewai_tool,
|
|
2275
2288
|
additional_imports_module_attr_map=additional_imports_module_attr_map,
|
|
2276
2289
|
)
|
|
2277
|
-
return self.server.tool_manager.create_or_update_tool(tool_create, actor=self.user)
|
|
2290
|
+
return self.server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=self.user)
|
|
2278
2291
|
|
|
2279
2292
|
def load_composio_tool(self, action: "ActionType") -> Tool:
|
|
2280
2293
|
tool_create = ToolCreate.from_composio(action=action)
|
|
2281
|
-
return self.server.tool_manager.create_or_update_tool(tool_create, actor=self.user)
|
|
2294
|
+
return self.server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=self.user)
|
|
2282
2295
|
|
|
2283
2296
|
# TODO: Use the above function `add_tool` here as there is duplicate logic
|
|
2284
2297
|
def create_tool(
|
|
@@ -2310,7 +2323,7 @@ class LocalClient(AbstractClient):
|
|
|
2310
2323
|
|
|
2311
2324
|
# call server function
|
|
2312
2325
|
return self.server.tool_manager.create_or_update_tool(
|
|
2313
|
-
|
|
2326
|
+
Tool(
|
|
2314
2327
|
source_type=source_type,
|
|
2315
2328
|
source_code=source_code,
|
|
2316
2329
|
name=name,
|
|
@@ -2738,7 +2751,7 @@ class LocalClient(AbstractClient):
|
|
|
2738
2751
|
return self.server.list_embedding_models()
|
|
2739
2752
|
|
|
2740
2753
|
def create_org(self, name: Optional[str] = None) -> Organization:
|
|
2741
|
-
return self.server.organization_manager.create_organization(name=name)
|
|
2754
|
+
return self.server.organization_manager.create_organization(pydantic_org=Organization(name=name))
|
|
2742
2755
|
|
|
2743
2756
|
def list_orgs(self, cursor: Optional[str] = None, limit: Optional[int] = 50) -> List[Organization]:
|
|
2744
2757
|
return self.server.organization_manager.list_organizations(cursor=cursor, limit=limit)
|
{letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/constants.py
RENAMED
|
@@ -18,6 +18,9 @@ IN_CONTEXT_MEMORY_KEYWORD = "CORE_MEMORY"
|
|
|
18
18
|
# OpenAI error message: Invalid 'messages[1].tool_calls[0].id': string too long. Expected a string with maximum length 29, but got a string with length 36 instead.
|
|
19
19
|
TOOL_CALL_ID_MAX_LEN = 29
|
|
20
20
|
|
|
21
|
+
# minimum context window size
|
|
22
|
+
MIN_CONTEXT_WINDOW = 4000
|
|
23
|
+
|
|
21
24
|
# embeddings
|
|
22
25
|
MAX_EMBEDDING_DIM = 4096 # maximum supported embeding size - do NOT change or else DBs will need to be reset
|
|
23
26
|
|
|
@@ -9,7 +9,7 @@ from letta.constants import CLI_WARNING_PREFIX
|
|
|
9
9
|
from letta.functions.schema_generator import generate_schema
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def derive_openai_json_schema(source_code: str, name: Optional[str]) -> dict:
|
|
12
|
+
def derive_openai_json_schema(source_code: str, name: Optional[str] = None) -> dict:
|
|
13
13
|
# auto-generate openai schema
|
|
14
14
|
try:
|
|
15
15
|
# Define a custom environment with necessary imports
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import warnings
|
|
2
1
|
from typing import Dict, List, Optional, Set
|
|
3
2
|
|
|
4
3
|
from pydantic import BaseModel, Field
|
|
@@ -67,7 +66,7 @@ class ToolRulesSolver(BaseModel):
|
|
|
67
66
|
if error_on_empty:
|
|
68
67
|
raise RuntimeError(message)
|
|
69
68
|
else:
|
|
70
|
-
warnings.warn(message)
|
|
69
|
+
# warnings.warn(message)
|
|
71
70
|
return []
|
|
72
71
|
|
|
73
72
|
def is_terminal_tool(self, tool_name: str) -> bool:
|
{letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/main.py
RENAMED
|
@@ -26,6 +26,9 @@ from letta.streaming_interface import AgentRefreshStreamingInterface
|
|
|
26
26
|
|
|
27
27
|
# interface = interface()
|
|
28
28
|
|
|
29
|
+
# disable composio print on exit
|
|
30
|
+
os.environ["COMPOSIO_DISABLE_VERSION_CHECK"] = "true"
|
|
31
|
+
|
|
29
32
|
app = typer.Typer(pretty_exceptions_enable=False)
|
|
30
33
|
app.command(name="run")(run)
|
|
31
34
|
app.command(name="version")(version)
|
{letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/metadata.py
RENAMED
|
@@ -493,6 +493,7 @@ class MetadataStore:
|
|
|
493
493
|
fields = vars(agent)
|
|
494
494
|
fields["memory"] = agent.memory.to_dict()
|
|
495
495
|
del fields["_internal_memory"]
|
|
496
|
+
del fields["tags"]
|
|
496
497
|
session.add(AgentModel(**fields))
|
|
497
498
|
session.commit()
|
|
498
499
|
|
|
@@ -531,6 +532,7 @@ class MetadataStore:
|
|
|
531
532
|
if isinstance(agent.memory, Memory): # TODO: this is nasty but this whole class will soon be removed so whatever
|
|
532
533
|
fields["memory"] = agent.memory.to_dict()
|
|
533
534
|
del fields["_internal_memory"]
|
|
535
|
+
del fields["tags"]
|
|
534
536
|
session.query(AgentModel).filter(AgentModel.id == agent.id).update(fields)
|
|
535
537
|
session.commit()
|
|
536
538
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import ForeignKey, String, UniqueConstraint
|
|
4
|
+
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
5
|
+
|
|
6
|
+
from letta.orm.mixins import OrganizationMixin
|
|
7
|
+
from letta.orm.sqlalchemy_base import SqlalchemyBase
|
|
8
|
+
from letta.schemas.agents_tags import AgentsTags as PydanticAgentsTags
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from letta.orm.organization import Organization
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AgentsTags(SqlalchemyBase, OrganizationMixin):
|
|
15
|
+
"""Associates tags with agents, allowing agents to have multiple tags and supporting tag-based filtering."""
|
|
16
|
+
|
|
17
|
+
__tablename__ = "agents_tags"
|
|
18
|
+
__pydantic_model__ = PydanticAgentsTags
|
|
19
|
+
__table_args__ = (UniqueConstraint("agent_id", "tag", name="unique_agent_tag"),)
|
|
20
|
+
|
|
21
|
+
# The agent associated with this tag
|
|
22
|
+
agent_id = mapped_column(String, ForeignKey("agents.id"), primary_key=True)
|
|
23
|
+
|
|
24
|
+
# The name of the tag
|
|
25
|
+
tag: Mapped[str] = mapped_column(String, nullable=False, doc="The name of the tag associated with the agent.")
|
|
26
|
+
|
|
27
|
+
# relationships
|
|
28
|
+
organization: Mapped["Organization"] = relationship("Organization", back_populates="agents_tags")
|
{letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/base.py
RENAMED
|
@@ -67,7 +67,7 @@ class CommonSqlalchemyMetaMixins(Base):
|
|
|
67
67
|
prop_value = getattr(self, full_prop, None)
|
|
68
68
|
if not prop_value:
|
|
69
69
|
return
|
|
70
|
-
return
|
|
70
|
+
return prop_value
|
|
71
71
|
|
|
72
72
|
def _user_id_setter(self, prop: str, value: str) -> None:
|
|
73
73
|
"""returns the user id for the specified property"""
|
|
@@ -75,6 +75,9 @@ class CommonSqlalchemyMetaMixins(Base):
|
|
|
75
75
|
if not value:
|
|
76
76
|
setattr(self, full_prop, None)
|
|
77
77
|
return
|
|
78
|
+
# Safety check
|
|
78
79
|
prefix, id_ = value.split("-", 1)
|
|
79
80
|
assert prefix == "user", f"{prefix} is not a valid id prefix for a user id"
|
|
80
|
-
|
|
81
|
+
|
|
82
|
+
# Set the full value
|
|
83
|
+
setattr(self, full_prop, value)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from uuid import UUID
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import ForeignKey, String
|
|
4
|
+
from sqlalchemy.orm import Mapped, mapped_column
|
|
5
|
+
|
|
6
|
+
from letta.orm.base import Base
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def is_valid_uuid4(uuid_string: str) -> bool:
|
|
10
|
+
"""Check if a string is a valid UUID4."""
|
|
11
|
+
try:
|
|
12
|
+
uuid_obj = UUID(uuid_string)
|
|
13
|
+
return uuid_obj.version == 4
|
|
14
|
+
except ValueError:
|
|
15
|
+
return False
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class OrganizationMixin(Base):
|
|
19
|
+
"""Mixin for models that belong to an organization."""
|
|
20
|
+
|
|
21
|
+
__abstract__ = True
|
|
22
|
+
|
|
23
|
+
organization_id: Mapped[str] = mapped_column(String, ForeignKey("organizations.id"))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class UserMixin(Base):
|
|
27
|
+
"""Mixin for models that belong to a user."""
|
|
28
|
+
|
|
29
|
+
__abstract__ = True
|
|
30
|
+
|
|
31
|
+
user_id: Mapped[str] = mapped_column(String, ForeignKey("users.id"))
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, List
|
|
2
2
|
|
|
3
|
+
from sqlalchemy import String
|
|
3
4
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
4
5
|
|
|
5
6
|
from letta.orm.sqlalchemy_base import SqlalchemyBase
|
|
@@ -14,13 +15,15 @@ if TYPE_CHECKING:
|
|
|
14
15
|
class Organization(SqlalchemyBase):
|
|
15
16
|
"""The highest level of the object tree. All Entities belong to one and only one Organization."""
|
|
16
17
|
|
|
17
|
-
__tablename__ = "
|
|
18
|
+
__tablename__ = "organizations"
|
|
18
19
|
__pydantic_model__ = PydanticOrganization
|
|
19
20
|
|
|
21
|
+
id: Mapped[str] = mapped_column(String, primary_key=True)
|
|
20
22
|
name: Mapped[str] = mapped_column(doc="The display name of the organization.")
|
|
21
23
|
|
|
22
24
|
users: Mapped[List["User"]] = relationship("User", back_populates="organization", cascade="all, delete-orphan")
|
|
23
25
|
tools: Mapped[List["Tool"]] = relationship("Tool", back_populates="organization", cascade="all, delete-orphan")
|
|
26
|
+
agents_tags: Mapped[List["AgentsTags"]] = relationship("AgentsTags", back_populates="organization", cascade="all, delete-orphan")
|
|
24
27
|
|
|
25
28
|
# TODO: Map these relationships later when we actually make these models
|
|
26
29
|
# below is just a suggestion
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, List, Literal, Optional, Type
|
|
2
|
-
from uuid import uuid4
|
|
3
2
|
|
|
4
|
-
from
|
|
5
|
-
from sqlalchemy import Boolean, String, select
|
|
3
|
+
from sqlalchemy import String, select
|
|
6
4
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
7
5
|
|
|
8
6
|
from letta.log import get_logger
|
|
9
7
|
from letta.orm.base import Base, CommonSqlalchemyMetaMixins
|
|
10
8
|
from letta.orm.errors import NoResultFound
|
|
11
|
-
from letta.orm.mixins import is_valid_uuid4
|
|
12
9
|
|
|
13
10
|
if TYPE_CHECKING:
|
|
14
11
|
from pydantic import BaseModel
|
|
@@ -24,27 +21,7 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
24
21
|
|
|
25
22
|
__order_by_default__ = "created_at"
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
deleted: Mapped[bool] = mapped_column(Boolean, default=False, doc="Is this record deleted? Used for universal soft deletes.")
|
|
30
|
-
|
|
31
|
-
@classmethod
|
|
32
|
-
def __prefix__(cls) -> str:
|
|
33
|
-
return depascalize(cls.__name__)
|
|
34
|
-
|
|
35
|
-
@property
|
|
36
|
-
def id(self) -> Optional[str]:
|
|
37
|
-
if self._id:
|
|
38
|
-
return f"{self.__prefix__()}-{self._id}"
|
|
39
|
-
|
|
40
|
-
@id.setter
|
|
41
|
-
def id(self, value: str) -> None:
|
|
42
|
-
if not value:
|
|
43
|
-
return
|
|
44
|
-
prefix, id_ = value.split("-", 1)
|
|
45
|
-
assert prefix == self.__prefix__(), f"{prefix} is not a valid id prefix for {self.__class__.__name__}"
|
|
46
|
-
assert is_valid_uuid4(id_), f"{id_} is not a valid uuid4"
|
|
47
|
-
self._id = id_
|
|
24
|
+
id: Mapped[str] = mapped_column(String, primary_key=True)
|
|
48
25
|
|
|
49
26
|
@classmethod
|
|
50
27
|
def list(
|
|
@@ -57,11 +34,10 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
57
34
|
|
|
58
35
|
# Add a cursor condition if provided
|
|
59
36
|
if cursor:
|
|
60
|
-
|
|
61
|
-
query = query.where(cls._id > cursor_uuid)
|
|
37
|
+
query = query.where(cls.id > cursor)
|
|
62
38
|
|
|
63
39
|
# Add a limit to the query if provided
|
|
64
|
-
query = query.order_by(cls.
|
|
40
|
+
query = query.order_by(cls.id).limit(limit)
|
|
65
41
|
|
|
66
42
|
# Handle soft deletes if the class has the 'is_deleted' attribute
|
|
67
43
|
if hasattr(cls, "is_deleted"):
|
|
@@ -70,20 +46,6 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
70
46
|
# Execute the query and return the results as a list of model instances
|
|
71
47
|
return list(session.execute(query).scalars())
|
|
72
48
|
|
|
73
|
-
@classmethod
|
|
74
|
-
def get_uid_from_identifier(cls, identifier: str, indifferent: Optional[bool] = False) -> str:
|
|
75
|
-
"""converts the id into a uuid object
|
|
76
|
-
Args:
|
|
77
|
-
identifier: the string identifier, such as `organization-xxxx-xx...`
|
|
78
|
-
indifferent: if True, will not enforce the prefix check
|
|
79
|
-
"""
|
|
80
|
-
try:
|
|
81
|
-
uuid_string = identifier.split("-", 1)[1] if indifferent else identifier.replace(f"{cls.__prefix__()}-", "")
|
|
82
|
-
assert is_valid_uuid4(uuid_string)
|
|
83
|
-
return uuid_string
|
|
84
|
-
except ValueError as e:
|
|
85
|
-
raise ValueError(f"{identifier} is not a valid identifier for class {cls.__name__}") from e
|
|
86
|
-
|
|
87
49
|
@classmethod
|
|
88
50
|
def read(
|
|
89
51
|
cls,
|
|
@@ -112,8 +74,7 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
112
74
|
|
|
113
75
|
# If an identifier is provided, add it to the query conditions
|
|
114
76
|
if identifier is not None:
|
|
115
|
-
|
|
116
|
-
query = query.where(cls._id == identifier)
|
|
77
|
+
query = query.where(cls.id == identifier)
|
|
117
78
|
query_conditions.append(f"id='{identifier}'")
|
|
118
79
|
|
|
119
80
|
if kwargs:
|
|
@@ -151,6 +112,22 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
151
112
|
self.is_deleted = True
|
|
152
113
|
return self.update(db_session)
|
|
153
114
|
|
|
115
|
+
def hard_delete(self, db_session: "Session", actor: Optional["User"] = None) -> None:
|
|
116
|
+
"""Permanently removes the record from the database."""
|
|
117
|
+
if actor:
|
|
118
|
+
logger.info(f"User {actor.id} requested hard deletion of {self.__class__.__name__} with ID {self.id}")
|
|
119
|
+
|
|
120
|
+
with db_session as session:
|
|
121
|
+
try:
|
|
122
|
+
session.delete(self)
|
|
123
|
+
session.commit()
|
|
124
|
+
except Exception as e:
|
|
125
|
+
session.rollback()
|
|
126
|
+
logger.exception(f"Failed to hard delete {self.__class__.__name__} with ID {self.id}")
|
|
127
|
+
raise ValueError(f"Failed to hard delete {self.__class__.__name__} with ID {self.id}: {e}")
|
|
128
|
+
else:
|
|
129
|
+
logger.info(f"{self.__class__.__name__} with ID {self.id} successfully hard deleted")
|
|
130
|
+
|
|
154
131
|
def update(self, db_session: "Session", actor: Optional["User"] = None) -> Type["SqlalchemyBase"]:
|
|
155
132
|
if actor:
|
|
156
133
|
self._set_created_and_updated_by_fields(actor.id)
|
|
@@ -183,7 +160,7 @@ class SqlalchemyBase(CommonSqlalchemyMetaMixins, Base):
|
|
|
183
160
|
org_id = getattr(actor, "organization_id", None)
|
|
184
161
|
if not org_id:
|
|
185
162
|
raise ValueError(f"object {actor} has no organization accessor")
|
|
186
|
-
return query.where(cls.
|
|
163
|
+
return query.where(cls.organization_id == org_id, cls.is_deleted == False)
|
|
187
164
|
|
|
188
165
|
@property
|
|
189
166
|
def __pydantic_model__(self) -> Type["BaseModel"]:
|
{letta_nightly-0.5.1.dev20241105104128 → letta_nightly-0.5.2.dev20241107104040}/letta/orm/tool.py
RENAMED
|
@@ -21,13 +21,14 @@ class Tool(SqlalchemyBase, OrganizationMixin):
|
|
|
21
21
|
more granular permissions.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
__tablename__ = "
|
|
24
|
+
__tablename__ = "tools"
|
|
25
25
|
__pydantic_model__ = PydanticTool
|
|
26
26
|
|
|
27
27
|
# Add unique constraint on (name, _organization_id)
|
|
28
28
|
# An organization should not have multiple tools with the same name
|
|
29
|
-
__table_args__ = (UniqueConstraint("name", "
|
|
29
|
+
__table_args__ = (UniqueConstraint("name", "organization_id", name="uix_name_organization"),)
|
|
30
30
|
|
|
31
|
+
id: Mapped[str] = mapped_column(String, primary_key=True)
|
|
31
32
|
name: Mapped[str] = mapped_column(doc="The display name of the tool.")
|
|
32
33
|
description: Mapped[Optional[str]] = mapped_column(nullable=True, doc="The description of the tool.")
|
|
33
34
|
tags: Mapped[List] = mapped_column(JSON, doc="Metadata tags used to filter tools.")
|