letta-nightly 0.6.14.dev20250123104106__py3-none-any.whl → 0.6.15.dev20250124054224__py3-none-any.whl
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/__init__.py +1 -1
- letta/client/client.py +144 -68
- letta/client/streaming.py +1 -1
- letta/functions/function_sets/extras.py +8 -3
- letta/functions/function_sets/multi_agent.py +1 -1
- letta/functions/helpers.py +2 -2
- letta/llm_api/llm_api_tools.py +2 -2
- letta/llm_api/openai.py +30 -138
- letta/memory.py +4 -4
- letta/offline_memory_agent.py +10 -10
- letta/orm/agent.py +10 -2
- letta/orm/block.py +14 -3
- letta/orm/job.py +2 -1
- letta/orm/message.py +12 -1
- letta/orm/passage.py +6 -2
- letta/orm/source.py +6 -1
- letta/orm/sqlalchemy_base.py +80 -32
- letta/orm/tool.py +5 -2
- letta/schemas/embedding_config_overrides.py +3 -0
- letta/schemas/enums.py +4 -0
- letta/schemas/job.py +1 -1
- letta/schemas/letta_message.py +22 -5
- letta/schemas/llm_config.py +5 -0
- letta/schemas/llm_config_overrides.py +38 -0
- letta/schemas/message.py +61 -15
- letta/schemas/openai/chat_completions.py +1 -1
- letta/schemas/passage.py +1 -1
- letta/schemas/providers.py +24 -8
- letta/schemas/source.py +1 -1
- letta/server/rest_api/app.py +12 -3
- letta/server/rest_api/interface.py +5 -7
- letta/server/rest_api/routers/v1/agents.py +7 -12
- letta/server/rest_api/routers/v1/blocks.py +19 -0
- letta/server/rest_api/routers/v1/organizations.py +2 -2
- letta/server/rest_api/routers/v1/providers.py +2 -2
- letta/server/rest_api/routers/v1/runs.py +15 -7
- letta/server/rest_api/routers/v1/sandbox_configs.py +4 -4
- letta/server/rest_api/routers/v1/sources.py +2 -2
- letta/server/rest_api/routers/v1/tags.py +2 -2
- letta/server/rest_api/routers/v1/tools.py +2 -2
- letta/server/rest_api/routers/v1/users.py +2 -2
- letta/server/server.py +62 -34
- letta/services/agent_manager.py +80 -33
- letta/services/block_manager.py +15 -2
- letta/services/helpers/agent_manager_helper.py +11 -4
- letta/services/job_manager.py +19 -9
- letta/services/message_manager.py +14 -8
- letta/services/organization_manager.py +8 -4
- letta/services/provider_manager.py +8 -4
- letta/services/sandbox_config_manager.py +16 -8
- letta/services/source_manager.py +4 -4
- letta/services/tool_manager.py +3 -3
- letta/services/user_manager.py +9 -5
- {letta_nightly-0.6.14.dev20250123104106.dist-info → letta_nightly-0.6.15.dev20250124054224.dist-info}/METADATA +2 -1
- {letta_nightly-0.6.14.dev20250123104106.dist-info → letta_nightly-0.6.15.dev20250124054224.dist-info}/RECORD +58 -57
- letta/orm/job_usage_statistics.py +0 -30
- {letta_nightly-0.6.14.dev20250123104106.dist-info → letta_nightly-0.6.15.dev20250124054224.dist-info}/LICENSE +0 -0
- {letta_nightly-0.6.14.dev20250123104106.dist-info → letta_nightly-0.6.15.dev20250124054224.dist-info}/WHEEL +0 -0
- {letta_nightly-0.6.14.dev20250123104106.dist-info → letta_nightly-0.6.15.dev20250124054224.dist-info}/entry_points.txt +0 -0
letta/__init__.py
CHANGED
letta/client/client.py
CHANGED
|
@@ -206,7 +206,7 @@ class AbstractClient(object):
|
|
|
206
206
|
) -> Tool:
|
|
207
207
|
raise NotImplementedError
|
|
208
208
|
|
|
209
|
-
def list_tools(self,
|
|
209
|
+
def list_tools(self, after: Optional[str] = None, limit: Optional[int] = 50) -> List[Tool]:
|
|
210
210
|
raise NotImplementedError
|
|
211
211
|
|
|
212
212
|
def get_tool(self, id: str) -> Tool:
|
|
@@ -266,7 +266,7 @@ class AbstractClient(object):
|
|
|
266
266
|
def list_attached_sources(self, agent_id: str) -> List[Source]:
|
|
267
267
|
raise NotImplementedError
|
|
268
268
|
|
|
269
|
-
def list_files_from_source(self, source_id: str, limit: int = 1000,
|
|
269
|
+
def list_files_from_source(self, source_id: str, limit: int = 1000, after: Optional[str] = None) -> List[FileMetadata]:
|
|
270
270
|
raise NotImplementedError
|
|
271
271
|
|
|
272
272
|
def update_source(self, source_id: str, name: Optional[str] = None) -> Source:
|
|
@@ -279,12 +279,12 @@ class AbstractClient(object):
|
|
|
279
279
|
raise NotImplementedError
|
|
280
280
|
|
|
281
281
|
def get_archival_memory(
|
|
282
|
-
self, agent_id: str,
|
|
282
|
+
self, agent_id: str, after: Optional[str] = None, before: Optional[str] = None, limit: Optional[int] = 1000
|
|
283
283
|
) -> List[Passage]:
|
|
284
284
|
raise NotImplementedError
|
|
285
285
|
|
|
286
286
|
def get_messages(
|
|
287
|
-
self, agent_id: str,
|
|
287
|
+
self, agent_id: str, after: Optional[str] = None, before: Optional[str] = None, limit: Optional[int] = 1000
|
|
288
288
|
) -> List[Message]:
|
|
289
289
|
raise NotImplementedError
|
|
290
290
|
|
|
@@ -297,7 +297,7 @@ class AbstractClient(object):
|
|
|
297
297
|
def create_org(self, name: Optional[str] = None) -> Organization:
|
|
298
298
|
raise NotImplementedError
|
|
299
299
|
|
|
300
|
-
def list_orgs(self,
|
|
300
|
+
def list_orgs(self, after: Optional[str] = None, limit: Optional[int] = 50) -> List[Organization]:
|
|
301
301
|
raise NotImplementedError
|
|
302
302
|
|
|
303
303
|
def delete_org(self, org_id: str) -> Organization:
|
|
@@ -337,13 +337,13 @@ class AbstractClient(object):
|
|
|
337
337
|
"""
|
|
338
338
|
raise NotImplementedError
|
|
339
339
|
|
|
340
|
-
def list_sandbox_configs(self, limit: int = 50,
|
|
340
|
+
def list_sandbox_configs(self, limit: int = 50, after: Optional[str] = None) -> List[SandboxConfig]:
|
|
341
341
|
"""
|
|
342
342
|
List all sandbox configurations.
|
|
343
343
|
|
|
344
344
|
Args:
|
|
345
345
|
limit (int, optional): The maximum number of sandbox configurations to return. Defaults to 50.
|
|
346
|
-
|
|
346
|
+
after (Optional[str], optional): The pagination cursor for retrieving the next set of results.
|
|
347
347
|
|
|
348
348
|
Returns:
|
|
349
349
|
List[SandboxConfig]: A list of sandbox configurations.
|
|
@@ -394,7 +394,7 @@ class AbstractClient(object):
|
|
|
394
394
|
raise NotImplementedError
|
|
395
395
|
|
|
396
396
|
def list_sandbox_env_vars(
|
|
397
|
-
self, sandbox_config_id: str, limit: int = 50,
|
|
397
|
+
self, sandbox_config_id: str, limit: int = 50, after: Optional[str] = None
|
|
398
398
|
) -> List[SandboxEnvironmentVariable]:
|
|
399
399
|
"""
|
|
400
400
|
List all environment variables associated with a sandbox configuration.
|
|
@@ -402,7 +402,7 @@ class AbstractClient(object):
|
|
|
402
402
|
Args:
|
|
403
403
|
sandbox_config_id (str): The ID of the sandbox configuration to retrieve environment variables for.
|
|
404
404
|
limit (int, optional): The maximum number of environment variables to return. Defaults to 50.
|
|
405
|
-
|
|
405
|
+
after (Optional[str], optional): The pagination cursor for retrieving the next set of results.
|
|
406
406
|
|
|
407
407
|
Returns:
|
|
408
408
|
List[SandboxEnvironmentVariable]: A list of environment variables.
|
|
@@ -477,7 +477,12 @@ class RESTClient(AbstractClient):
|
|
|
477
477
|
self._default_embedding_config = default_embedding_config
|
|
478
478
|
|
|
479
479
|
def list_agents(
|
|
480
|
-
self,
|
|
480
|
+
self,
|
|
481
|
+
tags: Optional[List[str]] = None,
|
|
482
|
+
query_text: Optional[str] = None,
|
|
483
|
+
limit: int = 50,
|
|
484
|
+
before: Optional[str] = None,
|
|
485
|
+
after: Optional[str] = None,
|
|
481
486
|
) -> List[AgentState]:
|
|
482
487
|
params = {"limit": limit}
|
|
483
488
|
if tags:
|
|
@@ -487,11 +492,13 @@ class RESTClient(AbstractClient):
|
|
|
487
492
|
if query_text:
|
|
488
493
|
params["query_text"] = query_text
|
|
489
494
|
|
|
490
|
-
if
|
|
491
|
-
params["
|
|
495
|
+
if before:
|
|
496
|
+
params["before"] = before
|
|
497
|
+
|
|
498
|
+
if after:
|
|
499
|
+
params["after"] = after
|
|
492
500
|
|
|
493
501
|
response = requests.get(f"{self.base_url}/{self.api_prefix}/agents", headers=self.headers, params=params)
|
|
494
|
-
print(f"\nLIST RESPONSE\n{response.json()}\n")
|
|
495
502
|
return [AgentState(**agent) for agent in response.json()]
|
|
496
503
|
|
|
497
504
|
def agent_exists(self, agent_id: str) -> bool:
|
|
@@ -636,7 +643,7 @@ class RESTClient(AbstractClient):
|
|
|
636
643
|
) -> Message:
|
|
637
644
|
request = MessageUpdate(
|
|
638
645
|
role=role,
|
|
639
|
-
|
|
646
|
+
content=text,
|
|
640
647
|
name=name,
|
|
641
648
|
tool_calls=tool_calls,
|
|
642
649
|
tool_call_id=tool_call_id,
|
|
@@ -1009,7 +1016,7 @@ class RESTClient(AbstractClient):
|
|
|
1009
1016
|
response (LettaResponse): Response from the agent
|
|
1010
1017
|
"""
|
|
1011
1018
|
# TODO: implement include_full_message
|
|
1012
|
-
messages = [MessageCreate(role=MessageRole(role),
|
|
1019
|
+
messages = [MessageCreate(role=MessageRole(role), content=message, name=name)]
|
|
1013
1020
|
# TODO: figure out how to handle stream_steps and stream_tokens
|
|
1014
1021
|
|
|
1015
1022
|
# When streaming steps is True, stream_tokens must be False
|
|
@@ -1056,7 +1063,7 @@ class RESTClient(AbstractClient):
|
|
|
1056
1063
|
Returns:
|
|
1057
1064
|
job (Job): Information about the async job
|
|
1058
1065
|
"""
|
|
1059
|
-
messages = [MessageCreate(role=MessageRole(role),
|
|
1066
|
+
messages = [MessageCreate(role=MessageRole(role), content=message, name=name)]
|
|
1060
1067
|
|
|
1061
1068
|
request = LettaRequest(messages=messages)
|
|
1062
1069
|
response = requests.post(
|
|
@@ -1359,7 +1366,7 @@ class RESTClient(AbstractClient):
|
|
|
1359
1366
|
def load_data(self, connector: DataConnector, source_name: str):
|
|
1360
1367
|
raise NotImplementedError
|
|
1361
1368
|
|
|
1362
|
-
def load_file_to_source(self, filename: str, source_id: str, blocking=True):
|
|
1369
|
+
def load_file_to_source(self, filename: str, source_id: str, blocking=True) -> Job:
|
|
1363
1370
|
"""
|
|
1364
1371
|
Load a file into a source
|
|
1365
1372
|
|
|
@@ -1427,20 +1434,20 @@ class RESTClient(AbstractClient):
|
|
|
1427
1434
|
raise ValueError(f"Failed to list attached sources: {response.text}")
|
|
1428
1435
|
return [Source(**source) for source in response.json()]
|
|
1429
1436
|
|
|
1430
|
-
def list_files_from_source(self, source_id: str, limit: int = 1000,
|
|
1437
|
+
def list_files_from_source(self, source_id: str, limit: int = 1000, after: Optional[str] = None) -> List[FileMetadata]:
|
|
1431
1438
|
"""
|
|
1432
1439
|
List files from source with pagination support.
|
|
1433
1440
|
|
|
1434
1441
|
Args:
|
|
1435
1442
|
source_id (str): ID of the source
|
|
1436
1443
|
limit (int): Number of files to return
|
|
1437
|
-
|
|
1444
|
+
after (str): Get files after a certain time
|
|
1438
1445
|
|
|
1439
1446
|
Returns:
|
|
1440
1447
|
List[FileMetadata]: List of files
|
|
1441
1448
|
"""
|
|
1442
1449
|
# Prepare query parameters for pagination
|
|
1443
|
-
params = {"limit": limit, "
|
|
1450
|
+
params = {"limit": limit, "after": after}
|
|
1444
1451
|
|
|
1445
1452
|
# Make the request to the FastAPI endpoint
|
|
1446
1453
|
response = requests.get(f"{self.base_url}/{self.api_prefix}/sources/{source_id}/files", headers=self.headers, params=params)
|
|
@@ -1640,7 +1647,7 @@ class RESTClient(AbstractClient):
|
|
|
1640
1647
|
raise ValueError(f"Failed to update tool: {response.text}")
|
|
1641
1648
|
return Tool(**response.json())
|
|
1642
1649
|
|
|
1643
|
-
def list_tools(self,
|
|
1650
|
+
def list_tools(self, after: Optional[str] = None, limit: Optional[int] = 50) -> List[Tool]:
|
|
1644
1651
|
"""
|
|
1645
1652
|
List available tools for the user.
|
|
1646
1653
|
|
|
@@ -1648,8 +1655,8 @@ class RESTClient(AbstractClient):
|
|
|
1648
1655
|
tools (List[Tool]): List of tools
|
|
1649
1656
|
"""
|
|
1650
1657
|
params = {}
|
|
1651
|
-
if
|
|
1652
|
-
params["
|
|
1658
|
+
if after:
|
|
1659
|
+
params["after"] = after
|
|
1653
1660
|
if limit:
|
|
1654
1661
|
params["limit"] = limit
|
|
1655
1662
|
|
|
@@ -1728,15 +1735,15 @@ class RESTClient(AbstractClient):
|
|
|
1728
1735
|
raise ValueError(f"Failed to list embedding configs: {response.text}")
|
|
1729
1736
|
return [EmbeddingConfig(**config) for config in response.json()]
|
|
1730
1737
|
|
|
1731
|
-
def list_orgs(self,
|
|
1738
|
+
def list_orgs(self, after: Optional[str] = None, limit: Optional[int] = 50) -> List[Organization]:
|
|
1732
1739
|
"""
|
|
1733
1740
|
Retrieves a list of all organizations in the database, with optional pagination.
|
|
1734
1741
|
|
|
1735
|
-
@param
|
|
1742
|
+
@param after: the pagination cursor, if any
|
|
1736
1743
|
@param limit: the maximum number of organizations to retrieve
|
|
1737
1744
|
@return: a list of Organization objects
|
|
1738
1745
|
"""
|
|
1739
|
-
params = {"
|
|
1746
|
+
params = {"after": after, "limit": limit}
|
|
1740
1747
|
response = requests.get(f"{self.base_url}/{ADMIN_PREFIX}/orgs", headers=self.headers, params=params)
|
|
1741
1748
|
if response.status_code != 200:
|
|
1742
1749
|
raise ValueError(f"Failed to retrieve organizations: {response.text}")
|
|
@@ -1779,6 +1786,12 @@ class RESTClient(AbstractClient):
|
|
|
1779
1786
|
def create_sandbox_config(self, config: Union[LocalSandboxConfig, E2BSandboxConfig]) -> SandboxConfig:
|
|
1780
1787
|
"""
|
|
1781
1788
|
Create a new sandbox configuration.
|
|
1789
|
+
|
|
1790
|
+
Args:
|
|
1791
|
+
config (Union[LocalSandboxConfig, E2BSandboxConfig]): The sandbox settings.
|
|
1792
|
+
|
|
1793
|
+
Returns:
|
|
1794
|
+
SandboxConfig: The created sandbox configuration.
|
|
1782
1795
|
"""
|
|
1783
1796
|
payload = {
|
|
1784
1797
|
"config": config.model_dump(),
|
|
@@ -1791,6 +1804,13 @@ class RESTClient(AbstractClient):
|
|
|
1791
1804
|
def update_sandbox_config(self, sandbox_config_id: str, config: Union[LocalSandboxConfig, E2BSandboxConfig]) -> SandboxConfig:
|
|
1792
1805
|
"""
|
|
1793
1806
|
Update an existing sandbox configuration.
|
|
1807
|
+
|
|
1808
|
+
Args:
|
|
1809
|
+
sandbox_config_id (str): The ID of the sandbox configuration to update.
|
|
1810
|
+
config (Union[LocalSandboxConfig, E2BSandboxConfig]): The updated sandbox settings.
|
|
1811
|
+
|
|
1812
|
+
Returns:
|
|
1813
|
+
SandboxConfig: The updated sandbox configuration.
|
|
1794
1814
|
"""
|
|
1795
1815
|
payload = {
|
|
1796
1816
|
"config": config.model_dump(),
|
|
@@ -1807,6 +1827,9 @@ class RESTClient(AbstractClient):
|
|
|
1807
1827
|
def delete_sandbox_config(self, sandbox_config_id: str) -> None:
|
|
1808
1828
|
"""
|
|
1809
1829
|
Delete a sandbox configuration.
|
|
1830
|
+
|
|
1831
|
+
Args:
|
|
1832
|
+
sandbox_config_id (str): The ID of the sandbox configuration to delete.
|
|
1810
1833
|
"""
|
|
1811
1834
|
response = requests.delete(f"{self.base_url}/{self.api_prefix}/sandbox-config/{sandbox_config_id}", headers=self.headers)
|
|
1812
1835
|
if response.status_code == 404:
|
|
@@ -1814,11 +1837,18 @@ class RESTClient(AbstractClient):
|
|
|
1814
1837
|
elif response.status_code != 204:
|
|
1815
1838
|
raise ValueError(f"Failed to delete sandbox config with ID '{sandbox_config_id}': {response.text}")
|
|
1816
1839
|
|
|
1817
|
-
def list_sandbox_configs(self, limit: int = 50,
|
|
1840
|
+
def list_sandbox_configs(self, limit: int = 50, after: Optional[str] = None) -> List[SandboxConfig]:
|
|
1818
1841
|
"""
|
|
1819
1842
|
List all sandbox configurations.
|
|
1843
|
+
|
|
1844
|
+
Args:
|
|
1845
|
+
limit (int, optional): The maximum number of sandbox configurations to return. Defaults to 50.
|
|
1846
|
+
after (Optional[str], optional): The pagination cursor for retrieving the next set of results.
|
|
1847
|
+
|
|
1848
|
+
Returns:
|
|
1849
|
+
List[SandboxConfig]: A list of sandbox configurations.
|
|
1820
1850
|
"""
|
|
1821
|
-
params = {"limit": limit, "
|
|
1851
|
+
params = {"limit": limit, "after": after}
|
|
1822
1852
|
response = requests.get(f"{self.base_url}/{self.api_prefix}/sandbox-config", headers=self.headers, params=params)
|
|
1823
1853
|
if response.status_code != 200:
|
|
1824
1854
|
raise ValueError(f"Failed to list sandbox configs: {response.text}")
|
|
@@ -1829,6 +1859,15 @@ class RESTClient(AbstractClient):
|
|
|
1829
1859
|
) -> SandboxEnvironmentVariable:
|
|
1830
1860
|
"""
|
|
1831
1861
|
Create a new environment variable for a sandbox configuration.
|
|
1862
|
+
|
|
1863
|
+
Args:
|
|
1864
|
+
sandbox_config_id (str): The ID of the sandbox configuration to associate the environment variable with.
|
|
1865
|
+
key (str): The name of the environment variable.
|
|
1866
|
+
value (str): The value of the environment variable.
|
|
1867
|
+
description (Optional[str], optional): A description of the environment variable. Defaults to None.
|
|
1868
|
+
|
|
1869
|
+
Returns:
|
|
1870
|
+
SandboxEnvironmentVariable: The created environment variable.
|
|
1832
1871
|
"""
|
|
1833
1872
|
payload = {"key": key, "value": value, "description": description}
|
|
1834
1873
|
response = requests.post(
|
|
@@ -1845,6 +1884,15 @@ class RESTClient(AbstractClient):
|
|
|
1845
1884
|
) -> SandboxEnvironmentVariable:
|
|
1846
1885
|
"""
|
|
1847
1886
|
Update an existing environment variable.
|
|
1887
|
+
|
|
1888
|
+
Args:
|
|
1889
|
+
env_var_id (str): The ID of the environment variable to update.
|
|
1890
|
+
key (Optional[str], optional): The updated name of the environment variable. Defaults to None.
|
|
1891
|
+
value (Optional[str], optional): The updated value of the environment variable. Defaults to None.
|
|
1892
|
+
description (Optional[str], optional): The updated description of the environment variable. Defaults to None.
|
|
1893
|
+
|
|
1894
|
+
Returns:
|
|
1895
|
+
SandboxEnvironmentVariable: The updated environment variable.
|
|
1848
1896
|
"""
|
|
1849
1897
|
payload = {k: v for k, v in {"key": key, "value": value, "description": description}.items() if v is not None}
|
|
1850
1898
|
response = requests.patch(
|
|
@@ -1859,6 +1907,9 @@ class RESTClient(AbstractClient):
|
|
|
1859
1907
|
def delete_sandbox_env_var(self, env_var_id: str) -> None:
|
|
1860
1908
|
"""
|
|
1861
1909
|
Delete an environment variable by its ID.
|
|
1910
|
+
|
|
1911
|
+
Args:
|
|
1912
|
+
env_var_id (str): The ID of the environment variable to delete.
|
|
1862
1913
|
"""
|
|
1863
1914
|
response = requests.delete(
|
|
1864
1915
|
f"{self.base_url}/{self.api_prefix}/sandbox-config/environment-variable/{env_var_id}", headers=self.headers
|
|
@@ -1869,12 +1920,20 @@ class RESTClient(AbstractClient):
|
|
|
1869
1920
|
raise ValueError(f"Failed to delete environment variable with ID '{env_var_id}': {response.text}")
|
|
1870
1921
|
|
|
1871
1922
|
def list_sandbox_env_vars(
|
|
1872
|
-
self, sandbox_config_id: str, limit: int = 50,
|
|
1923
|
+
self, sandbox_config_id: str, limit: int = 50, after: Optional[str] = None
|
|
1873
1924
|
) -> List[SandboxEnvironmentVariable]:
|
|
1874
1925
|
"""
|
|
1875
1926
|
List all environment variables associated with a sandbox configuration.
|
|
1927
|
+
|
|
1928
|
+
Args:
|
|
1929
|
+
sandbox_config_id (str): The ID of the sandbox configuration to retrieve environment variables for.
|
|
1930
|
+
limit (int, optional): The maximum number of environment variables to return. Defaults to 50.
|
|
1931
|
+
after (Optional[str], optional): The pagination cursor for retrieving the next set of results.
|
|
1932
|
+
|
|
1933
|
+
Returns:
|
|
1934
|
+
List[SandboxEnvironmentVariable]: A list of environment variables.
|
|
1876
1935
|
"""
|
|
1877
|
-
params = {"limit": limit, "
|
|
1936
|
+
params = {"limit": limit, "after": after}
|
|
1878
1937
|
response = requests.get(
|
|
1879
1938
|
f"{self.base_url}/{self.api_prefix}/sandbox-config/{sandbox_config_id}/environment-variable",
|
|
1880
1939
|
headers=self.headers,
|
|
@@ -2035,7 +2094,8 @@ class RESTClient(AbstractClient):
|
|
|
2035
2094
|
def get_run_messages(
|
|
2036
2095
|
self,
|
|
2037
2096
|
run_id: str,
|
|
2038
|
-
|
|
2097
|
+
before: Optional[str] = None,
|
|
2098
|
+
after: Optional[str] = None,
|
|
2039
2099
|
limit: Optional[int] = 100,
|
|
2040
2100
|
ascending: bool = True,
|
|
2041
2101
|
role: Optional[MessageRole] = None,
|
|
@@ -2045,7 +2105,8 @@ class RESTClient(AbstractClient):
|
|
|
2045
2105
|
|
|
2046
2106
|
Args:
|
|
2047
2107
|
job_id: ID of the job
|
|
2048
|
-
|
|
2108
|
+
before: Cursor for pagination
|
|
2109
|
+
after: Cursor for pagination
|
|
2049
2110
|
limit: Maximum number of messages to return
|
|
2050
2111
|
ascending: Sort order by creation time
|
|
2051
2112
|
role: Filter by message role (user/assistant/system/tool)
|
|
@@ -2053,7 +2114,8 @@ class RESTClient(AbstractClient):
|
|
|
2053
2114
|
List of messages matching the filter criteria
|
|
2054
2115
|
"""
|
|
2055
2116
|
params = {
|
|
2056
|
-
"
|
|
2117
|
+
"before": before,
|
|
2118
|
+
"after": after,
|
|
2057
2119
|
"limit": limit,
|
|
2058
2120
|
"ascending": ascending,
|
|
2059
2121
|
"role": role,
|
|
@@ -2151,15 +2213,15 @@ class RESTClient(AbstractClient):
|
|
|
2151
2213
|
|
|
2152
2214
|
def get_tags(
|
|
2153
2215
|
self,
|
|
2154
|
-
|
|
2155
|
-
limit:
|
|
2216
|
+
after: Optional[str] = None,
|
|
2217
|
+
limit: int = 100,
|
|
2156
2218
|
query_text: Optional[str] = None,
|
|
2157
2219
|
) -> List[str]:
|
|
2158
2220
|
"""
|
|
2159
2221
|
Get a list of all unique tags.
|
|
2160
2222
|
|
|
2161
2223
|
Args:
|
|
2162
|
-
|
|
2224
|
+
after: Optional cursor for pagination (first tag seen)
|
|
2163
2225
|
limit: Optional maximum number of tags to return
|
|
2164
2226
|
query_text: Optional text to filter tags
|
|
2165
2227
|
|
|
@@ -2167,8 +2229,8 @@ class RESTClient(AbstractClient):
|
|
|
2167
2229
|
List[str]: List of unique tags
|
|
2168
2230
|
"""
|
|
2169
2231
|
params = {}
|
|
2170
|
-
if
|
|
2171
|
-
params["
|
|
2232
|
+
if after:
|
|
2233
|
+
params["after"] = after
|
|
2172
2234
|
if limit:
|
|
2173
2235
|
params["limit"] = limit
|
|
2174
2236
|
if query_text:
|
|
@@ -2238,11 +2300,18 @@ class LocalClient(AbstractClient):
|
|
|
2238
2300
|
|
|
2239
2301
|
# agents
|
|
2240
2302
|
def list_agents(
|
|
2241
|
-
self,
|
|
2303
|
+
self,
|
|
2304
|
+
query_text: Optional[str] = None,
|
|
2305
|
+
tags: Optional[List[str]] = None,
|
|
2306
|
+
limit: int = 100,
|
|
2307
|
+
before: Optional[str] = None,
|
|
2308
|
+
after: Optional[str] = None,
|
|
2242
2309
|
) -> List[AgentState]:
|
|
2243
2310
|
self.interface.clear()
|
|
2244
2311
|
|
|
2245
|
-
return self.server.agent_manager.list_agents(
|
|
2312
|
+
return self.server.agent_manager.list_agents(
|
|
2313
|
+
actor=self.user, tags=tags, query_text=query_text, limit=limit, before=before, after=after
|
|
2314
|
+
)
|
|
2246
2315
|
|
|
2247
2316
|
def agent_exists(self, agent_id: Optional[str] = None, agent_name: Optional[str] = None) -> bool:
|
|
2248
2317
|
"""
|
|
@@ -2374,7 +2443,7 @@ class LocalClient(AbstractClient):
|
|
|
2374
2443
|
message_id=message_id,
|
|
2375
2444
|
request=MessageUpdate(
|
|
2376
2445
|
role=role,
|
|
2377
|
-
|
|
2446
|
+
content=text,
|
|
2378
2447
|
name=name,
|
|
2379
2448
|
tool_calls=tool_calls,
|
|
2380
2449
|
tool_call_id=tool_call_id,
|
|
@@ -2673,7 +2742,7 @@ class LocalClient(AbstractClient):
|
|
|
2673
2742
|
usage = self.server.send_messages(
|
|
2674
2743
|
actor=self.user,
|
|
2675
2744
|
agent_id=agent_id,
|
|
2676
|
-
messages=[MessageCreate(role=MessageRole(role),
|
|
2745
|
+
messages=[MessageCreate(role=MessageRole(role), content=message, name=name)],
|
|
2677
2746
|
)
|
|
2678
2747
|
|
|
2679
2748
|
## TODO: need to make sure date/timestamp is propely passed
|
|
@@ -2990,7 +3059,7 @@ class LocalClient(AbstractClient):
|
|
|
2990
3059
|
id: str,
|
|
2991
3060
|
name: Optional[str] = None,
|
|
2992
3061
|
description: Optional[str] = None,
|
|
2993
|
-
func: Optional[
|
|
3062
|
+
func: Optional[Callable] = None,
|
|
2994
3063
|
tags: Optional[List[str]] = None,
|
|
2995
3064
|
return_char_limit: int = FUNCTION_RETURN_CHAR_LIMIT,
|
|
2996
3065
|
) -> Tool:
|
|
@@ -3021,14 +3090,14 @@ class LocalClient(AbstractClient):
|
|
|
3021
3090
|
|
|
3022
3091
|
return self.server.tool_manager.update_tool_by_id(tool_id=id, tool_update=ToolUpdate(**update_data), actor=self.user)
|
|
3023
3092
|
|
|
3024
|
-
def list_tools(self,
|
|
3093
|
+
def list_tools(self, after: Optional[str] = None, limit: Optional[int] = 50) -> List[Tool]:
|
|
3025
3094
|
"""
|
|
3026
3095
|
List available tools for the user.
|
|
3027
3096
|
|
|
3028
3097
|
Returns:
|
|
3029
3098
|
tools (List[Tool]): List of tools
|
|
3030
3099
|
"""
|
|
3031
|
-
return self.server.tool_manager.list_tools(
|
|
3100
|
+
return self.server.tool_manager.list_tools(after=after, limit=limit, actor=self.user)
|
|
3032
3101
|
|
|
3033
3102
|
def get_tool(self, id: str) -> Optional[Tool]:
|
|
3034
3103
|
"""
|
|
@@ -3227,19 +3296,19 @@ class LocalClient(AbstractClient):
|
|
|
3227
3296
|
"""
|
|
3228
3297
|
return self.server.agent_manager.list_attached_sources(agent_id=agent_id, actor=self.user)
|
|
3229
3298
|
|
|
3230
|
-
def list_files_from_source(self, source_id: str, limit: int = 1000,
|
|
3299
|
+
def list_files_from_source(self, source_id: str, limit: int = 1000, after: Optional[str] = None) -> List[FileMetadata]:
|
|
3231
3300
|
"""
|
|
3232
3301
|
List files from source.
|
|
3233
3302
|
|
|
3234
3303
|
Args:
|
|
3235
3304
|
source_id (str): ID of the source
|
|
3236
3305
|
limit (int): The # of items to return
|
|
3237
|
-
|
|
3306
|
+
after (str): The cursor for fetching the next page
|
|
3238
3307
|
|
|
3239
3308
|
Returns:
|
|
3240
3309
|
files (List[FileMetadata]): List of files
|
|
3241
3310
|
"""
|
|
3242
|
-
return self.server.source_manager.list_files(source_id=source_id, limit=limit,
|
|
3311
|
+
return self.server.source_manager.list_files(source_id=source_id, limit=limit, after=after, actor=self.user)
|
|
3243
3312
|
|
|
3244
3313
|
def update_source(self, source_id: str, name: Optional[str] = None) -> Source:
|
|
3245
3314
|
"""
|
|
@@ -3297,17 +3366,20 @@ class LocalClient(AbstractClient):
|
|
|
3297
3366
|
passages (List[Passage]): List of passages
|
|
3298
3367
|
"""
|
|
3299
3368
|
|
|
3300
|
-
return self.server.
|
|
3369
|
+
return self.server.get_agent_archival(user_id=self.user_id, agent_id=agent_id, limit=limit)
|
|
3301
3370
|
|
|
3302
3371
|
# recall memory
|
|
3303
3372
|
|
|
3304
|
-
def get_messages(
|
|
3373
|
+
def get_messages(
|
|
3374
|
+
self, agent_id: str, before: Optional[str] = None, after: Optional[str] = None, limit: Optional[int] = 1000
|
|
3375
|
+
) -> List[Message]:
|
|
3305
3376
|
"""
|
|
3306
3377
|
Get messages from an agent with pagination.
|
|
3307
3378
|
|
|
3308
3379
|
Args:
|
|
3309
3380
|
agent_id (str): ID of the agent
|
|
3310
|
-
|
|
3381
|
+
before (str): Get messages before a certain time
|
|
3382
|
+
after (str): Get messages after a certain time
|
|
3311
3383
|
limit (int): Limit number of messages
|
|
3312
3384
|
|
|
3313
3385
|
Returns:
|
|
@@ -3315,10 +3387,11 @@ class LocalClient(AbstractClient):
|
|
|
3315
3387
|
"""
|
|
3316
3388
|
|
|
3317
3389
|
self.interface.clear()
|
|
3318
|
-
return self.server.
|
|
3390
|
+
return self.server.get_agent_recall(
|
|
3319
3391
|
user_id=self.user_id,
|
|
3320
3392
|
agent_id=agent_id,
|
|
3321
|
-
before=
|
|
3393
|
+
before=before,
|
|
3394
|
+
after=after,
|
|
3322
3395
|
limit=limit,
|
|
3323
3396
|
reverse=True,
|
|
3324
3397
|
)
|
|
@@ -3437,8 +3510,8 @@ class LocalClient(AbstractClient):
|
|
|
3437
3510
|
def create_org(self, name: Optional[str] = None) -> Organization:
|
|
3438
3511
|
return self.server.organization_manager.create_organization(pydantic_org=Organization(name=name))
|
|
3439
3512
|
|
|
3440
|
-
def list_orgs(self,
|
|
3441
|
-
return self.server.organization_manager.list_organizations(
|
|
3513
|
+
def list_orgs(self, after: Optional[str] = None, limit: Optional[int] = 50) -> List[Organization]:
|
|
3514
|
+
return self.server.organization_manager.list_organizations(limit=limit, after=after)
|
|
3442
3515
|
|
|
3443
3516
|
def delete_org(self, org_id: str) -> Organization:
|
|
3444
3517
|
return self.server.organization_manager.delete_organization_by_id(org_id=org_id)
|
|
@@ -3465,11 +3538,11 @@ class LocalClient(AbstractClient):
|
|
|
3465
3538
|
"""
|
|
3466
3539
|
return self.server.sandbox_config_manager.delete_sandbox_config(sandbox_config_id=sandbox_config_id, actor=self.user)
|
|
3467
3540
|
|
|
3468
|
-
def list_sandbox_configs(self, limit: int = 50,
|
|
3541
|
+
def list_sandbox_configs(self, limit: int = 50, after: Optional[str] = None) -> List[SandboxConfig]:
|
|
3469
3542
|
"""
|
|
3470
3543
|
List all sandbox configurations.
|
|
3471
3544
|
"""
|
|
3472
|
-
return self.server.sandbox_config_manager.list_sandbox_configs(actor=self.user, limit=limit,
|
|
3545
|
+
return self.server.sandbox_config_manager.list_sandbox_configs(actor=self.user, limit=limit, after=after)
|
|
3473
3546
|
|
|
3474
3547
|
def create_sandbox_env_var(
|
|
3475
3548
|
self, sandbox_config_id: str, key: str, value: str, description: Optional[str] = None
|
|
@@ -3500,13 +3573,13 @@ class LocalClient(AbstractClient):
|
|
|
3500
3573
|
return self.server.sandbox_config_manager.delete_sandbox_env_var(env_var_id=env_var_id, actor=self.user)
|
|
3501
3574
|
|
|
3502
3575
|
def list_sandbox_env_vars(
|
|
3503
|
-
self, sandbox_config_id: str, limit: int = 50,
|
|
3576
|
+
self, sandbox_config_id: str, limit: int = 50, after: Optional[str] = None
|
|
3504
3577
|
) -> List[SandboxEnvironmentVariable]:
|
|
3505
3578
|
"""
|
|
3506
3579
|
List all environment variables associated with a sandbox configuration.
|
|
3507
3580
|
"""
|
|
3508
3581
|
return self.server.sandbox_config_manager.list_sandbox_env_vars(
|
|
3509
|
-
sandbox_config_id=sandbox_config_id, actor=self.user, limit=limit,
|
|
3582
|
+
sandbox_config_id=sandbox_config_id, actor=self.user, limit=limit, after=after
|
|
3510
3583
|
)
|
|
3511
3584
|
|
|
3512
3585
|
def update_agent_memory_block_label(self, agent_id: str, current_label: str, new_label: str) -> Memory:
|
|
@@ -3627,7 +3700,8 @@ class LocalClient(AbstractClient):
|
|
|
3627
3700
|
def get_run_messages(
|
|
3628
3701
|
self,
|
|
3629
3702
|
run_id: str,
|
|
3630
|
-
|
|
3703
|
+
before: Optional[str] = None,
|
|
3704
|
+
after: Optional[str] = None,
|
|
3631
3705
|
limit: Optional[int] = 100,
|
|
3632
3706
|
ascending: bool = True,
|
|
3633
3707
|
role: Optional[MessageRole] = None,
|
|
@@ -3637,21 +3711,23 @@ class LocalClient(AbstractClient):
|
|
|
3637
3711
|
|
|
3638
3712
|
Args:
|
|
3639
3713
|
run_id: ID of the run
|
|
3640
|
-
|
|
3714
|
+
before: Cursor for pagination
|
|
3715
|
+
after: Cursor for pagination
|
|
3641
3716
|
limit: Maximum number of messages to return
|
|
3642
3717
|
ascending: Sort order by creation time
|
|
3643
3718
|
role: Filter by message role (user/assistant/system/tool)
|
|
3644
|
-
|
|
3645
3719
|
Returns:
|
|
3646
3720
|
List of messages matching the filter criteria
|
|
3647
3721
|
"""
|
|
3648
3722
|
params = {
|
|
3649
|
-
"
|
|
3723
|
+
"before": before,
|
|
3724
|
+
"after": after,
|
|
3650
3725
|
"limit": limit,
|
|
3651
3726
|
"ascending": ascending,
|
|
3652
3727
|
"role": role,
|
|
3653
3728
|
}
|
|
3654
|
-
|
|
3729
|
+
|
|
3730
|
+
return self.server.job_manager.get_run_messages(run_id=run_id, actor=self.user, **params)
|
|
3655
3731
|
|
|
3656
3732
|
def get_run_usage(
|
|
3657
3733
|
self,
|
|
@@ -3713,9 +3789,9 @@ class LocalClient(AbstractClient):
|
|
|
3713
3789
|
|
|
3714
3790
|
def get_tags(
|
|
3715
3791
|
self,
|
|
3716
|
-
|
|
3717
|
-
limit: int =
|
|
3718
|
-
query_text: str = None,
|
|
3792
|
+
after: Optional[str] = None,
|
|
3793
|
+
limit: Optional[int] = None,
|
|
3794
|
+
query_text: Optional[str] = None,
|
|
3719
3795
|
) -> List[str]:
|
|
3720
3796
|
"""
|
|
3721
3797
|
Get all tags.
|
|
@@ -3723,4 +3799,4 @@ class LocalClient(AbstractClient):
|
|
|
3723
3799
|
Returns:
|
|
3724
3800
|
tags (List[str]): List of tags
|
|
3725
3801
|
"""
|
|
3726
|
-
return self.server.agent_manager.list_tags(actor=self.user,
|
|
3802
|
+
return self.server.agent_manager.list_tags(actor=self.user, after=after, limit=limit, query_text=query_text)
|
letta/client/streaming.py
CHANGED
|
@@ -50,7 +50,7 @@ def _sse_post(url: str, data: dict, headers: dict) -> Generator[LettaStreamingRe
|
|
|
50
50
|
chunk_data = json.loads(sse.data)
|
|
51
51
|
if "reasoning" in chunk_data:
|
|
52
52
|
yield ReasoningMessage(**chunk_data)
|
|
53
|
-
elif "
|
|
53
|
+
elif "message_type" in chunk_data and chunk_data["message_type"] == "assistant_message":
|
|
54
54
|
yield AssistantMessage(**chunk_data)
|
|
55
55
|
elif "tool_call" in chunk_data:
|
|
56
56
|
yield ToolCallMessage(**chunk_data)
|
|
@@ -6,7 +6,7 @@ import requests
|
|
|
6
6
|
|
|
7
7
|
from letta.constants import MESSAGE_CHATGPT_FUNCTION_MODEL, MESSAGE_CHATGPT_FUNCTION_SYSTEM_MESSAGE
|
|
8
8
|
from letta.llm_api.llm_api_tools import create
|
|
9
|
-
from letta.schemas.message import Message
|
|
9
|
+
from letta.schemas.message import Message, TextContent
|
|
10
10
|
from letta.utils import json_dumps, json_loads
|
|
11
11
|
|
|
12
12
|
|
|
@@ -23,8 +23,13 @@ def message_chatgpt(self, message: str):
|
|
|
23
23
|
dummy_user_id = uuid.uuid4()
|
|
24
24
|
dummy_agent_id = uuid.uuid4()
|
|
25
25
|
message_sequence = [
|
|
26
|
-
Message(
|
|
27
|
-
|
|
26
|
+
Message(
|
|
27
|
+
user_id=dummy_user_id,
|
|
28
|
+
agent_id=dummy_agent_id,
|
|
29
|
+
role="system",
|
|
30
|
+
content=[TextContent(text=MESSAGE_CHATGPT_FUNCTION_SYSTEM_MESSAGE)],
|
|
31
|
+
),
|
|
32
|
+
Message(user_id=dummy_user_id, agent_id=dummy_agent_id, role="user", content=[TextContent(text=str(message))]),
|
|
28
33
|
]
|
|
29
34
|
# TODO: this will error without an LLMConfig
|
|
30
35
|
response = create(
|
|
@@ -74,7 +74,7 @@ def send_message_to_agents_matching_all_tags(self: "Agent", message: str, tags:
|
|
|
74
74
|
server = get_letta_server()
|
|
75
75
|
|
|
76
76
|
# Retrieve agents that match ALL specified tags
|
|
77
|
-
matching_agents = server.agent_manager.list_agents(actor=self.user, tags=tags, match_all_tags=True,
|
|
77
|
+
matching_agents = server.agent_manager.list_agents(actor=self.user, tags=tags, match_all_tags=True, limit=100)
|
|
78
78
|
|
|
79
79
|
async def send_messages_to_all_agents():
|
|
80
80
|
tasks = [
|
letta/functions/helpers.py
CHANGED
|
@@ -246,7 +246,7 @@ def parse_letta_response_for_assistant_message(
|
|
|
246
246
|
reasoning_message = ""
|
|
247
247
|
for m in letta_response.messages:
|
|
248
248
|
if isinstance(m, AssistantMessage):
|
|
249
|
-
return m.
|
|
249
|
+
return m.content
|
|
250
250
|
elif isinstance(m, ToolCallMessage) and m.tool_call.name == assistant_message_tool_name:
|
|
251
251
|
try:
|
|
252
252
|
return json.loads(m.tool_call.arguments)[assistant_message_tool_kwarg]
|
|
@@ -290,7 +290,7 @@ async def async_send_message_with_retries(
|
|
|
290
290
|
logging_prefix = logging_prefix or "[async_send_message_with_retries]"
|
|
291
291
|
for attempt in range(1, max_retries + 1):
|
|
292
292
|
try:
|
|
293
|
-
messages = [MessageCreate(role=MessageRole.user,
|
|
293
|
+
messages = [MessageCreate(role=MessageRole.user, content=message_text, name=sender_agent.agent_state.name)]
|
|
294
294
|
# Wrap in a timeout
|
|
295
295
|
response = await asyncio.wait_for(
|
|
296
296
|
server.send_message_to_agent(
|