From 55c3fbba3f5883aa2c468e67aff850326f935e7c Mon Sep 17 00:00:00 2001 From: Sarah Wooders Date: Mon, 21 Apr 2025 00:09:50 -0700 Subject: [PATCH] chore: add sleeptime example + better error handling + upgrade client SDK (#1809) --- examples/sleeptime/sleeptime_example.py | 59 ++++++++++++++ .../sleeptime/sleeptime_source_example.py | 76 +++++++++++++++++++ letta/constants.py | 6 +- letta/data_sources/connectors.py | 8 +- letta/errors.py | 10 +++ letta/server/server.py | 9 ++- poetry.lock | 52 ++++++++++++- pyproject.toml | 2 +- tests/test_client.py | 12 +-- tests/test_sdk_client.py | 27 +++---- 10 files changed, 228 insertions(+), 33 deletions(-) create mode 100644 examples/sleeptime/sleeptime_example.py create mode 100644 examples/sleeptime/sleeptime_source_example.py diff --git a/examples/sleeptime/sleeptime_example.py b/examples/sleeptime/sleeptime_example.py new file mode 100644 index 00000000..2d42a1de --- /dev/null +++ b/examples/sleeptime/sleeptime_example.py @@ -0,0 +1,59 @@ +from letta_client import Letta, SleeptimeManagerUpdate + +client = Letta(base_url="http://localhost:8283") + +agent = client.agents.create( + memory_blocks=[ + {"value": "Name: ?", "label": "human"}, + {"value": "You are a helpful assistant.", "label": "persona"}, + ], + model="openai/gpt-4.1", + embedding="openai/text-embedding-3-small", + enable_sleeptime=True, +) +print(f"Created agent id {agent.id}") + +# get the group +group_id = agent.multi_agent_group.id +current_frequence = agent.multi_agent_group.sleeptime_agent_frequency +print(f"Group id: {group_id}, frequency: {current_frequence}") + +group = client.groups.modify( + group_id=group_id, + manager_config=SleeptimeManagerUpdate( + sleeptime_agent_frequency=1 + ), +) +print(f"Updated group id {group_id} with frequency {group.sleeptime_agent_frequency}") +print(f"Group members", group.agent_ids) +sleeptime_ids = [] +for agent_id in group.agent_ids: + if client.agents.retrieve(agent_id=agent_id).agent_type == "sleeptime_agent": + sleeptime_ids.append(agent_id) +print(f"Sleeptime agent ids: {sleeptime_ids}") +sleeptime_agent_id = sleeptime_ids[0] + +# check the frequency +agent = client.agents.retrieve(agent_id=agent.id) +print(f"Updated agent id {agent.id} with frequency {agent.multi_agent_group.sleeptime_agent_frequency}") + + +response = client.agents.messages.create( + agent_id=agent.id, + messages=[ + {"role": "user", "content": "Hello can you echo back this input?"}, + ], +) +response = client.agents.messages.create( + agent_id=agent.id, + messages=[ + {"role": "user", "content": "My name is sarah"}, + ], +) +for message in response.messages: + print(message) + +print("---------------- SLEEPTIME AGENT ----------------") +for message in client.agents.messages.list(agent_id=sleeptime_agent_id): + print(message) + diff --git a/examples/sleeptime/sleeptime_source_example.py b/examples/sleeptime/sleeptime_source_example.py new file mode 100644 index 00000000..e6a3ad75 --- /dev/null +++ b/examples/sleeptime/sleeptime_source_example.py @@ -0,0 +1,76 @@ +import time + +from letta_client import AgentType, GroupUpdateManagerConfig, Letta, ManagerType, SleeptimeManagerUpdate +from letta_client.types import agent_type + +client = Letta(base_url="http://localhost:8283") + +# delete all sources +for source in client.sources.list(): + print(f"Deleting source {source.name}") + client.sources.delete(source.id) + +agent = client.agents.create( + memory_blocks=[ + {"value": "Name: ?", "label": "human"}, + {"value": "You are a helpful assistant.", "label": "persona"}, + ], + model="openai/gpt-4.1", + embedding="openai/text-embedding-3-small", + enable_sleeptime=True, +) +print(f"Created agent id {agent.id}") + +# get the group +group_id = agent.multi_agent_group.id +current_frequence = agent.multi_agent_group.sleeptime_agent_frequency +print(f"Group id: {group_id}, frequency: {current_frequence}") + +# create a source +source_name = "employee_handbook" +source = client.sources.create( + name=source_name, + description="Provides reference information for the employee handbook", + embedding="openai/text-embedding-ada-002" # must match agent +) +# attach the source to the agent +client.agents.sources.attach( + source_id=source.id, + agent_id=agent.id +) + +# upload a file: this will trigger processing +job = client.sources.files.upload( + file=open("handbook.pdf", "rb"), + source_id=source.id +) + +time.sleep(2) + +# get employee handbook block (same name as the source) +print("Agent blocks", [b.label for b in client.agents.blocks.list(agent_id=agent.id)]) +block = client.agents.blocks.retrieve(agent_id=agent.id, block_label="employee_handbook") + + +# get attached agents +agents = client.blocks.agents.list(block_id=block.id) +for agent in agents: + print(f"Agent id {agent.id}", agent.agent_type) + print("Agent blocks:") + for b in client.agents.blocks.list(agent_id=agent.id): + print(f"Block {b.label}:", b.value) + +while job.status != "completed": + job = client.jobs.retrieve(job.id) + + # count passages + passages = client.agents.passages.list(agent_id=agent.id) + print(f"Passages {len(passages)}") + for passage in passages: + print(passage.text) + + time.sleep(2) + + + + diff --git a/letta/constants.py b/letta/constants.py index 57e85b1f..b8913503 100644 --- a/letta/constants.py +++ b/letta/constants.py @@ -60,9 +60,9 @@ BASE_SLEEPTIME_TOOLS = [ "memory_insert", "memory_rethink", "memory_finish_edits", - "archival_memory_insert", - "archival_memory_search", - "conversation_search", + # "archival_memory_insert", + # "archival_memory_search", + # "conversation_search", ] # Multi agent tools MULTI_AGENT_TOOLS = ["send_message_to_agent_and_wait_for_reply", "send_message_to_agents_matching_tags", "send_message_to_agent_async"] diff --git a/letta/data_sources/connectors.py b/letta/data_sources/connectors.py index 12408ca6..188b37b7 100644 --- a/letta/data_sources/connectors.py +++ b/letta/data_sources/connectors.py @@ -159,7 +159,13 @@ class DirectoryConnector(DataConnector): from llama_index.core.node_parser import TokenTextSplitter parser = TokenTextSplitter(chunk_size=chunk_size) - documents = SimpleDirectoryReader(input_files=[file.file_path]).load_data() + if file.file_type == "application/pdf": + from llama_index.readers.file import PDFReader + + reader = PDFReader() + documents = reader.load_data(file=file.file_path) + else: + documents = SimpleDirectoryReader(input_files=[file.file_path]).load_data() nodes = parser.get_nodes_from_documents(documents) for node in nodes: yield node.text, None diff --git a/letta/errors.py b/letta/errors.py index 6598dff2..17427ea6 100644 --- a/letta/errors.py +++ b/letta/errors.py @@ -204,3 +204,13 @@ class InvalidInnerMonologueError(LettaMessageError): """Error raised when a message has a malformed inner monologue.""" default_error_message = "The message has a malformed inner monologue." + + +class HandleNotFoundError(LettaError): + """Error raised when a handle is not found.""" + + def __init__(self, handle: str, available_handles: List[str]): + super().__init__( + message=f"Handle {handle} not found, must be one of {available_handles}", + code=ErrorCode.NOT_FOUND, + ) diff --git a/letta/server/server.py b/letta/server/server.py index 81b09b20..70e63520 100644 --- a/letta/server/server.py +++ b/letta/server/server.py @@ -20,6 +20,7 @@ import letta.system as system from letta.agent import Agent, save_agent from letta.config import LettaConfig from letta.data_sources.connectors import DataConnector, load_data +from letta.errors import HandleNotFoundError from letta.functions.mcp_client.base_client import BaseMCPClient from letta.functions.mcp_client.sse_client import MCP_CONFIG_TOPLEVEL_KEY, SSEMCPClient from letta.functions.mcp_client.stdio_client import StdioMCPClient @@ -702,6 +703,8 @@ class SyncServer(Server): @trace_method def get_cached_llm_config(self, **kwargs): key = make_key(**kwargs) + print(self._llm_config_cache) + print("KEY", key) if key not in self._llm_config_cache: self._llm_config_cache[key] = self.get_llm_config_from_handle(**kwargs) return self._llm_config_cache[key] @@ -1179,10 +1182,12 @@ class SyncServer(Server): provider = self.get_provider_from_name(provider_name) llm_configs = [config for config in provider.list_llm_models() if config.handle == handle] + print("LLM CONFIGS", llm_configs) if not llm_configs: llm_configs = [config for config in provider.list_llm_models() if config.model == model_name] if not llm_configs: - raise ValueError(f"LLM model {model_name} is not supported by {provider_name}") + available_handles = [config.handle for config in provider.list_llm_models()] + raise HandleNotFoundError(handle, available_handles) except ValueError as e: llm_configs = [config for config in self.get_local_llm_configs() if config.handle == handle] if not llm_configs: @@ -1190,6 +1195,8 @@ class SyncServer(Server): if not llm_configs: raise e + print("CONFIGS", llm_configs) + if len(llm_configs) == 1: llm_config = llm_configs[0] elif len(llm_configs) > 1: diff --git a/poetry.lock b/poetry.lock index 5a412260..f4728e40 100644 --- a/poetry.lock +++ b/poetry.lock @@ -563,6 +563,10 @@ files = [ {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a37b8f0391212d29b3a91a799c8e4a2855e0576911cdfb2515487e30e322253d"}, {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0"}, {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e"}, + {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c"}, + {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1"}, + {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2"}, + {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec"}, {file = "Brotli-1.1.0-cp310-cp310-win32.whl", hash = "sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2"}, {file = "Brotli-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128"}, {file = "Brotli-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a3daabb76a78f829cafc365531c972016e4aa8d5b4bf60660ad8ecee19df7ccc"}, @@ -575,8 +579,14 @@ files = [ {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9"}, {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265"}, {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a1fd8a29719ccce974d523580987b7f8229aeace506952fa9ce1d53a033873c8"}, + {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c247dd99d39e0338a604f8c2b3bc7061d5c2e9e2ac7ba9cc1be5a69cb6cd832f"}, + {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1b2c248cd517c222d89e74669a4adfa5577e06ab68771a529060cf5a156e9757"}, + {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2a24c50840d89ded6c9a8fdc7b6ed3692ed4e86f1c4a4a938e1e92def92933e0"}, + {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f31859074d57b4639318523d6ffdca586ace54271a73ad23ad021acd807eb14b"}, {file = "Brotli-1.1.0-cp311-cp311-win32.whl", hash = "sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50"}, {file = "Brotli-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1"}, + {file = "Brotli-1.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28"}, + {file = "Brotli-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f"}, {file = "Brotli-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409"}, {file = "Brotli-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2"}, {file = "Brotli-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451"}, @@ -587,8 +597,24 @@ files = [ {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180"}, {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248"}, {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966"}, + {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9"}, + {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb"}, + {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111"}, + {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839"}, {file = "Brotli-1.1.0-cp312-cp312-win32.whl", hash = "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0"}, {file = "Brotli-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951"}, + {file = "Brotli-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5"}, + {file = "Brotli-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8"}, + {file = "Brotli-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f"}, + {file = "Brotli-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648"}, + {file = "Brotli-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0"}, + {file = "Brotli-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089"}, + {file = "Brotli-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368"}, + {file = "Brotli-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c"}, + {file = "Brotli-1.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284"}, + {file = "Brotli-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7"}, + {file = "Brotli-1.1.0-cp313-cp313-win32.whl", hash = "sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0"}, + {file = "Brotli-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b"}, {file = "Brotli-1.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1"}, {file = "Brotli-1.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d"}, {file = "Brotli-1.1.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b"}, @@ -598,6 +624,10 @@ files = [ {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:fd5f17ff8f14003595ab414e45fce13d073e0762394f957182e69035c9f3d7c2"}, {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354"}, {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2"}, + {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:aea440a510e14e818e67bfc4027880e2fb500c2ccb20ab21c7a7c8b5b4703d75"}, + {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:6974f52a02321b36847cd19d1b8e381bf39939c21efd6ee2fc13a28b0d99348c"}, + {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:a7e53012d2853a07a4a79c00643832161a910674a893d296c9f1259859a289d2"}, + {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:d7702622a8b40c49bffb46e1e3ba2e81268d5c04a34f460978c6b5517a34dd52"}, {file = "Brotli-1.1.0-cp36-cp36m-win32.whl", hash = "sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460"}, {file = "Brotli-1.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579"}, {file = "Brotli-1.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c"}, @@ -609,6 +639,10 @@ files = [ {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74"}, {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b"}, {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438"}, + {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:cb1dac1770878ade83f2ccdf7d25e494f05c9165f5246b46a621cc849341dc01"}, + {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:3ee8a80d67a4334482d9712b8e83ca6b1d9bc7e351931252ebef5d8f7335a547"}, + {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:5e55da2c8724191e5b557f8e18943b1b4839b8efc3ef60d65985bcf6f587dd38"}, + {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:d342778ef319e1026af243ed0a07c97acf3bad33b9f29e7ae6a1f68fd083e90c"}, {file = "Brotli-1.1.0-cp37-cp37m-win32.whl", hash = "sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95"}, {file = "Brotli-1.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68"}, {file = "Brotli-1.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3"}, @@ -621,6 +655,10 @@ files = [ {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a"}, {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:141bd4d93984070e097521ed07e2575b46f817d08f9fa42b16b9b5f27b5ac088"}, {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596"}, + {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d2b35ca2c7f81d173d2fadc2f4f31e88cc5f7a39ae5b6db5513cf3383b0e0ec7"}, + {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:af6fa6817889314555aede9a919612b23739395ce767fe7fcbea9a80bf140fe5"}, + {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:2feb1d960f760a575dbc5ab3b1c00504b24caaf6986e2dc2b01c09c87866a943"}, + {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4410f84b33374409552ac9b6903507cdb31cd30d2501fc5ca13d18f73548444a"}, {file = "Brotli-1.1.0-cp38-cp38-win32.whl", hash = "sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b"}, {file = "Brotli-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0"}, {file = "Brotli-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a"}, @@ -633,6 +671,10 @@ files = [ {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c"}, {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d"}, {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59"}, + {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0737ddb3068957cf1b054899b0883830bb1fec522ec76b1098f9b6e0f02d9419"}, + {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4f3607b129417e111e30637af1b56f24f7a49e64763253bbc275c75fa887d4b2"}, + {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:6c6e0c425f22c1c719c42670d561ad682f7bfeeef918edea971a79ac5252437f"}, + {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:494994f807ba0b92092a163a0a283961369a65f6cbe01e8891132b7a320e61eb"}, {file = "Brotli-1.1.0-cp39-cp39-win32.whl", hash = "sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64"}, {file = "Brotli-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467"}, {file = "Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724"}, @@ -3026,13 +3068,13 @@ pytest = ["pytest (>=7.0.0)", "rich (>=13.9.4,<14.0.0)"] [[package]] name = "letta-client" -version = "0.1.105" +version = "0.1.124" description = "" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "letta_client-0.1.105-py3-none-any.whl", hash = "sha256:d39792603d34725f2cd8dd7b9b0431ff535a4c4be1ddf697a194e9fced5f329b"}, - {file = "letta_client-0.1.105.tar.gz", hash = "sha256:b694187d3908357cfd89c986070aea14a25504139c7325678e8dc86a74d8814f"}, + {file = "letta_client-0.1.124-py3-none-any.whl", hash = "sha256:a7901437ef91f395cd85d24c0312046b7c82e5a4dd8e04de0d39b5ca085c65d3"}, + {file = "letta_client-0.1.124.tar.gz", hash = "sha256:e8b5716930824cc98c62ee01343e358f88619d346578d48a466277bc8282036d"}, ] [package.dependencies] @@ -4746,6 +4788,7 @@ files = [ {file = "psycopg2-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:0435034157049f6846e95103bd8f5a668788dd913a7c30162ca9503fdf542cb4"}, {file = "psycopg2-2.9.10-cp312-cp312-win32.whl", hash = "sha256:65a63d7ab0e067e2cdb3cf266de39663203d38d6a8ed97f5ca0cb315c73fe067"}, {file = "psycopg2-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:4a579d6243da40a7b3182e0430493dbd55950c493d8c68f4eec0b302f6bbf20e"}, + {file = "psycopg2-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:91fd603a2155da8d0cfcdbf8ab24a2d54bca72795b90d2a3ed2b6da8d979dee2"}, {file = "psycopg2-2.9.10-cp39-cp39-win32.whl", hash = "sha256:9d5b3b94b79a844a986d029eee38998232451119ad653aea42bb9220a8c5066b"}, {file = "psycopg2-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:88138c8dedcbfa96408023ea2b0c369eda40fe5d75002c0964c78f46f11fa442"}, {file = "psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11"}, @@ -4805,6 +4848,7 @@ files = [ {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, @@ -7170,4 +7214,4 @@ tests = ["wikipedia"] [metadata] lock-version = "2.0" python-versions = "<3.14,>=3.10" -content-hash = "5fd927f0519033fb00c3769ab81d682019e532697a374457c50faf4f75bdca02" +content-hash = "75c1c949aa6c0ef8d681bddd91999f97ed4991451be93ca45bf9c01dd19d8a8a" diff --git a/pyproject.toml b/pyproject.toml index 2fe4292c..866ba8d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ llama-index = "^0.12.2" llama-index-embeddings-openai = "^0.3.1" e2b-code-interpreter = {version = "^1.0.3", optional = true} anthropic = "^0.49.0" -letta_client = "^0.1.104" +letta_client = "^0.1.124" openai = "^1.60.0" opentelemetry-api = "1.30.0" opentelemetry-sdk = "1.30.0" diff --git a/tests/test_client.py b/tests/test_client.py index 10121100..280e50c7 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -232,30 +232,30 @@ def test_agent_tags(client: Letta): ) # Test getting all tags - all_tags = client.tag.list_tags() + all_tags = client.tags.list() expected_tags = ["agent1", "agent2", "agent3", "development", "production", "test"] assert sorted(all_tags) == expected_tags # Test pagination - paginated_tags = client.tag.list_tags(limit=2) + paginated_tags = client.tags.list(limit=2) assert len(paginated_tags) == 2 assert paginated_tags[0] == "agent1" assert paginated_tags[1] == "agent2" # Test pagination with cursor - next_page_tags = client.tag.list_tags(after="agent2", limit=2) + next_page_tags = client.tags.list(after="agent2", limit=2) assert len(next_page_tags) == 2 assert next_page_tags[0] == "agent3" assert next_page_tags[1] == "development" # Test text search - prod_tags = client.tag.list_tags(query_text="prod") + prod_tags = client.tags.list(query_text="prod") assert sorted(prod_tags) == ["production"] - dev_tags = client.tag.list_tags(query_text="dev") + dev_tags = client.tags.list(query_text="dev") assert sorted(dev_tags) == ["development"] - agent_tags = client.tag.list_tags(query_text="agent") + agent_tags = client.tags.list(query_text="agent") assert sorted(agent_tags) == ["agent1", "agent2", "agent3"] # Remove agents diff --git a/tests/test_sdk_client.py b/tests/test_sdk_client.py index 232092cd..ffa4758f 100644 --- a/tests/test_sdk_client.py +++ b/tests/test_sdk_client.py @@ -218,30 +218,30 @@ def test_agent_tags(client: LettaSDKClient): ) # Test getting all tags - all_tags = client.tag.list_tags() + all_tags = client.tags.list() expected_tags = ["agent1", "agent2", "agent3", "development", "production", "test"] assert sorted(all_tags) == expected_tags # Test pagination - paginated_tags = client.tag.list_tags(limit=2) + paginated_tags = client.tags.list(limit=2) assert len(paginated_tags) == 2 assert paginated_tags[0] == "agent1" assert paginated_tags[1] == "agent2" # Test pagination with cursor - next_page_tags = client.tag.list_tags(after="agent2", limit=2) + next_page_tags = client.tags.list(after="agent2", limit=2) assert len(next_page_tags) == 2 assert next_page_tags[0] == "agent3" assert next_page_tags[1] == "development" # Test text search - prod_tags = client.tag.list_tags(query_text="prod") + prod_tags = client.tags.list(query_text="prod") assert sorted(prod_tags) == ["production"] - dev_tags = client.tag.list_tags(query_text="dev") + dev_tags = client.tags.list(query_text="dev") assert sorted(dev_tags) == ["development"] - agent_tags = client.tag.list_tags(query_text="agent") + agent_tags = client.tags.list(query_text="agent") assert sorted(agent_tags) == ["agent1", "agent2", "agent3"] # Remove agents @@ -504,7 +504,7 @@ def test_send_message_async(client: LettaSDKClient, agent: AgentState): start_time = time.time() while run.status == "created": time.sleep(1) - run = client.runs.retrieve_run(run_id=run.id) + run = client.runs.retrieve(run_id=run.id) print(f"Run status: {run.status}") if time.time() - start_time > 10: pytest.fail("Run took too long to complete") @@ -513,26 +513,19 @@ def test_send_message_async(client: LettaSDKClient, agent: AgentState): assert run.status == "completed" # Get messages for the job - messages = client.runs.list_run_messages(run_id=run.id) + messages = client.runs.messages.list(run_id=run.id) assert len(messages) >= 2 # At least assistant response # Check filters - assistant_messages = client.runs.list_run_messages(run_id=run.id, role="assistant") + assistant_messages = client.runs.messages.list(run_id=run.id, role="assistant") assert len(assistant_messages) > 0 - tool_messages = client.runs.list_run_messages(run_id=run.id, role="tool") + tool_messages = client.runs.messages.list(run_id=run.id, role="tool") assert len(tool_messages) > 0 # specific_tool_messages = [message for message in client.runs.list_run_messages(run_id=run.id) if isinstance(message, ToolCallMessage)] # assert specific_tool_messages[0].tool_call.name == "send_message" # assert len(specific_tool_messages) > 0 - # Get and verify usage statistics - usage = client.runs.retrieve_run_usage(run_id=run.id) - assert usage.completion_tokens >= 0 - assert usage.prompt_tokens >= 0 - assert usage.total_tokens >= 0 - assert usage.total_tokens == usage.completion_tokens + usage.prompt_tokens - def test_agent_creation(client: LettaSDKClient): """Test that block IDs are properly attached when creating an agent."""