letta-nightly 0.5.0.dev20241018104142__py3-none-any.whl → 0.5.0.dev20241019104023__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/agent.py CHANGED
@@ -23,7 +23,7 @@ from letta.errors import LLMError
23
23
  from letta.interface import AgentInterface
24
24
  from letta.llm_api.helpers import is_context_overflow_error
25
25
  from letta.llm_api.llm_api_tools import create
26
- from letta.local_llm.utils import num_tokens_from_messages
26
+ from letta.local_llm.utils import num_tokens_from_functions, num_tokens_from_messages
27
27
  from letta.memory import ArchivalMemory, RecallMemory, summarize_messages
28
28
  from letta.metadata import MetadataStore
29
29
  from letta.persistence_manager import LocalStateManager
@@ -33,6 +33,9 @@ from letta.schemas.embedding_config import EmbeddingConfig
33
33
  from letta.schemas.enums import MessageRole
34
34
  from letta.schemas.memory import ContextWindowOverview, Memory
35
35
  from letta.schemas.message import Message, UpdateMessage
36
+ from letta.schemas.openai.chat_completion_request import (
37
+ Tool as ChatCompletionRequestTool,
38
+ )
36
39
  from letta.schemas.openai.chat_completion_response import ChatCompletionResponse
37
40
  from letta.schemas.openai.chat_completion_response import (
38
41
  Message as ChatCompletionMessage,
@@ -1458,6 +1461,24 @@ class Agent(BaseAgent):
1458
1461
  )
1459
1462
  num_tokens_external_memory_summary = count_tokens(external_memory_summary)
1460
1463
 
1464
+ # tokens taken up by function definitions
1465
+ if self.functions:
1466
+ available_functions_definitions = [ChatCompletionRequestTool(type="function", function=f) for f in self.functions]
1467
+ num_tokens_available_functions_definitions = num_tokens_from_functions(functions=self.functions, model=self.model)
1468
+ else:
1469
+ available_functions_definitions = []
1470
+ num_tokens_available_functions_definitions = 0
1471
+
1472
+ num_tokens_used_total = (
1473
+ num_tokens_system # system prompt
1474
+ + num_tokens_available_functions_definitions # function definitions
1475
+ + num_tokens_core_memory # core memory
1476
+ + num_tokens_external_memory_summary # metadata (statistics) about recall/archival
1477
+ + num_tokens_summary_memory # summary of ongoing conversation
1478
+ + num_tokens_messages # tokens taken by messages
1479
+ )
1480
+ assert isinstance(num_tokens_used_total, int)
1481
+
1461
1482
  return ContextWindowOverview(
1462
1483
  # context window breakdown (in messages)
1463
1484
  num_messages=len(self._messages),
@@ -1466,7 +1487,7 @@ class Agent(BaseAgent):
1466
1487
  num_tokens_external_memory_summary=num_tokens_external_memory_summary,
1467
1488
  # top-level information
1468
1489
  context_window_size_max=self.agent_state.llm_config.context_window,
1469
- context_window_size_current=num_tokens_system + num_tokens_core_memory + num_tokens_summary_memory + num_tokens_messages,
1490
+ context_window_size_current=num_tokens_used_total,
1470
1491
  # context window breakdown (in tokens)
1471
1492
  num_tokens_system=num_tokens_system,
1472
1493
  system_prompt=system_prompt,
@@ -1476,6 +1497,9 @@ class Agent(BaseAgent):
1476
1497
  summary_memory=summary_memory,
1477
1498
  num_tokens_messages=num_tokens_messages,
1478
1499
  messages=self._messages,
1500
+ # related to functions
1501
+ num_tokens_functions_definitions=num_tokens_available_functions_definitions,
1502
+ functions_definitions=available_functions_definitions,
1479
1503
  )
1480
1504
 
1481
1505
 
letta/client/client.py CHANGED
@@ -96,6 +96,9 @@ class AbstractClient(object):
96
96
  ):
97
97
  raise NotImplementedError
98
98
 
99
+ def get_tools_from_agent(self, agent_id: str):
100
+ raise NotImplementedError
101
+
99
102
  def add_tool_to_agent(self, agent_id: str, tool_id: str):
100
103
  raise NotImplementedError
101
104
 
@@ -197,7 +200,7 @@ class AbstractClient(object):
197
200
  ) -> Tool:
198
201
  raise NotImplementedError
199
202
 
200
- def list_tools(self) -> List[Tool]:
203
+ def list_tools(self, cursor: Optional[str] = None, limit: Optional[int] = 50) -> List[Tool]:
201
204
  raise NotImplementedError
202
205
 
203
206
  def get_tool(self, id: str) -> Tool:
@@ -480,6 +483,21 @@ class RESTClient(AbstractClient):
480
483
  raise ValueError(f"Failed to update agent: {response.text}")
481
484
  return AgentState(**response.json())
482
485
 
486
+ def get_tools_from_agent(self, agent_id: str) -> List[Tool]:
487
+ """
488
+ Get tools to an existing agent
489
+
490
+ Args:
491
+ agent_id (str): ID of the agent
492
+
493
+ Returns:
494
+ List[Tool]: A List of Tool objs
495
+ """
496
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/agents/{agent_id}/tools", headers=self.headers)
497
+ if response.status_code != 200:
498
+ raise ValueError(f"Failed to get tools from agents: {response.text}")
499
+ return [Tool(**tool) for tool in response.json()]
500
+
483
501
  def add_tool_to_agent(self, agent_id: str, tool_id: str):
484
502
  """
485
503
  Add tool to an existing agent
@@ -1364,14 +1382,19 @@ class RESTClient(AbstractClient):
1364
1382
  # raise ValueError(f"Failed to create tool: {response.text}")
1365
1383
  # return ToolModel(**response.json())
1366
1384
 
1367
- def list_tools(self) -> List[Tool]:
1385
+ def list_tools(self, cursor: Optional[str] = None, limit: Optional[int] = 50) -> List[Tool]:
1368
1386
  """
1369
1387
  List available tools for the user.
1370
1388
 
1371
1389
  Returns:
1372
1390
  tools (List[Tool]): List of tools
1373
1391
  """
1374
- response = requests.get(f"{self.base_url}/{self.api_prefix}/tools", headers=self.headers)
1392
+ params = {}
1393
+ if cursor:
1394
+ params["cursor"] = str(cursor)
1395
+ if limit:
1396
+ params["limit"] = limit
1397
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/tools", params=params, headers=self.headers)
1375
1398
  if response.status_code != 200:
1376
1399
  raise ValueError(f"Failed to list tools: {response.text}")
1377
1400
  return [Tool(**tool) for tool in response.json()]
@@ -1692,6 +1715,19 @@ class LocalClient(AbstractClient):
1692
1715
  )
1693
1716
  return agent_state
1694
1717
 
1718
+ def get_tools_from_agent(self, agent_id: str) -> List[Tool]:
1719
+ """
1720
+ Get tools from an existing agent.
1721
+
1722
+ Args:
1723
+ agent_id (str): ID of the agent
1724
+
1725
+ Returns:
1726
+ List[Tool]: A list of Tool objs
1727
+ """
1728
+ self.interface.clear()
1729
+ return self.server.get_tools_from_agent(agent_id=agent_id, user_id=self.user_id)
1730
+
1695
1731
  def add_tool_to_agent(self, agent_id: str, tool_id: str):
1696
1732
  """
1697
1733
  Add tool to an existing agent
@@ -2250,15 +2286,14 @@ class LocalClient(AbstractClient):
2250
2286
  ToolUpdate(id=id, source_type=source_type, source_code=source_code, tags=tags, name=name), self.user_id
2251
2287
  )
2252
2288
 
2253
- def list_tools(self):
2289
+ def list_tools(self, cursor: Optional[str] = None, limit: Optional[int] = 50) -> List[Tool]:
2254
2290
  """
2255
2291
  List available tools for the user.
2256
2292
 
2257
2293
  Returns:
2258
2294
  tools (List[Tool]): List of tools
2259
2295
  """
2260
- tools = self.server.list_tools(user_id=self.user_id)
2261
- return tools
2296
+ return self.server.list_tools(cursor=cursor, limit=limit, user_id=self.user_id)
2262
2297
 
2263
2298
  def get_tool(self, id: str) -> Optional[Tool]:
2264
2299
  """
letta/llm_api/openai.py CHANGED
@@ -18,8 +18,13 @@ from letta.local_llm.utils import num_tokens_from_functions, num_tokens_from_mes
18
18
  from letta.schemas.llm_config import LLMConfig
19
19
  from letta.schemas.message import Message as _Message
20
20
  from letta.schemas.message import MessageRole as _MessageRole
21
+ from letta.schemas.openai.chat_completion_request import ChatCompletionRequest
21
22
  from letta.schemas.openai.chat_completion_request import (
22
- ChatCompletionRequest,
23
+ FunctionCall as ToolFunctionChoiceFunctionCall,
24
+ )
25
+ from letta.schemas.openai.chat_completion_request import (
26
+ Tool,
27
+ ToolFunctionChoice,
23
28
  cast_message_to_subtype,
24
29
  )
25
30
  from letta.schemas.openai.chat_completion_response import (
@@ -100,10 +105,10 @@ def openai_get_model_list(
100
105
 
101
106
  def build_openai_chat_completions_request(
102
107
  llm_config: LLMConfig,
103
- messages: List[Message],
108
+ messages: List[_Message],
104
109
  user_id: Optional[str],
105
110
  functions: Optional[list],
106
- function_call: str,
111
+ function_call: Optional[str],
107
112
  use_tool_naming: bool,
108
113
  max_tokens: Optional[int],
109
114
  ) -> ChatCompletionRequest:
@@ -124,11 +129,17 @@ def build_openai_chat_completions_request(
124
129
  model = None
125
130
 
126
131
  if use_tool_naming:
132
+ if function_call is None:
133
+ tool_choice = None
134
+ elif function_call not in ["none", "auto", "required"]:
135
+ tool_choice = ToolFunctionChoice(type="function", function=ToolFunctionChoiceFunctionCall(name=function_call))
136
+ else:
137
+ tool_choice = function_call
127
138
  data = ChatCompletionRequest(
128
139
  model=model,
129
140
  messages=openai_message_list,
130
- tools=[{"type": "function", "function": f} for f in functions] if functions else None,
131
- tool_choice=function_call,
141
+ tools=[Tool(type="function", function=f) for f in functions] if functions else None,
142
+ tool_choice=tool_choice,
132
143
  user=str(user_id),
133
144
  max_tokens=max_tokens,
134
145
  )
letta/local_llm/utils.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  import warnings
3
- from typing import List
3
+ from typing import List, Union
4
4
 
5
5
  import requests
6
6
  import tiktoken
@@ -11,6 +11,7 @@ import letta.local_llm.llm_chat_completion_wrappers.configurable_wrapper as conf
11
11
  import letta.local_llm.llm_chat_completion_wrappers.dolphin as dolphin
12
12
  import letta.local_llm.llm_chat_completion_wrappers.llama3 as llama3
13
13
  import letta.local_llm.llm_chat_completion_wrappers.zephyr as zephyr
14
+ from letta.schemas.openai.chat_completion_request import Tool, ToolCall
14
15
 
15
16
 
16
17
  def post_json_auth_request(uri, json_payload, auth_type, auth_key):
@@ -123,7 +124,7 @@ def num_tokens_from_functions(functions: List[dict], model: str = "gpt-4"):
123
124
  return num_tokens
124
125
 
125
126
 
126
- def num_tokens_from_tool_calls(tool_calls: List[dict], model: str = "gpt-4"):
127
+ def num_tokens_from_tool_calls(tool_calls: Union[List[dict], List[ToolCall]], model: str = "gpt-4"):
127
128
  """Based on above code (num_tokens_from_functions).
128
129
 
129
130
  Example to encode:
@@ -144,10 +145,25 @@ def num_tokens_from_tool_calls(tool_calls: List[dict], model: str = "gpt-4"):
144
145
 
145
146
  num_tokens = 0
146
147
  for tool_call in tool_calls:
147
- function_tokens = len(encoding.encode(tool_call["id"]))
148
- function_tokens += 2 + len(encoding.encode(tool_call["type"]))
149
- function_tokens += 2 + len(encoding.encode(tool_call["function"]["name"]))
150
- function_tokens += 2 + len(encoding.encode(tool_call["function"]["arguments"]))
148
+ if isinstance(tool_call, dict):
149
+ tool_call_id = tool_call["id"]
150
+ tool_call_type = tool_call["type"]
151
+ tool_call_function = tool_call["function"]
152
+ tool_call_function_name = tool_call_function["name"]
153
+ tool_call_function_arguments = tool_call_function["arguments"]
154
+ elif isinstance(tool_call, Tool):
155
+ tool_call_id = tool_call.id
156
+ tool_call_type = tool_call.type
157
+ tool_call_function = tool_call.function
158
+ tool_call_function_name = tool_call_function.name
159
+ tool_call_function_arguments = tool_call_function.arguments
160
+ else:
161
+ raise ValueError(f"Unknown tool call type: {type(tool_call)}")
162
+
163
+ function_tokens = len(encoding.encode(tool_call_id))
164
+ function_tokens += 2 + len(encoding.encode(tool_call_type))
165
+ function_tokens += 2 + len(encoding.encode(tool_call_function_name))
166
+ function_tokens += 2 + len(encoding.encode(tool_call_function_arguments))
151
167
 
152
168
  num_tokens += function_tokens
153
169
 
letta/metadata.py CHANGED
@@ -14,7 +14,9 @@ from sqlalchemy import (
14
14
  Integer,
15
15
  String,
16
16
  TypeDecorator,
17
+ asc,
17
18
  desc,
19
+ or_,
18
20
  )
19
21
  from sqlalchemy.sql import func
20
22
 
@@ -707,12 +709,19 @@ class MetadataStore:
707
709
  session.commit()
708
710
 
709
711
  @enforce_types
710
- # def list_tools(self, user_id: str) -> List[ToolModel]: # TODO: add when users can creat tools
711
- def list_tools(self, user_id: Optional[str] = None) -> List[ToolModel]:
712
+ def list_tools(self, cursor: Optional[str] = None, limit: Optional[int] = 50, user_id: Optional[str] = None) -> List[ToolModel]:
712
713
  with self.session_maker() as session:
713
- results = session.query(ToolModel).filter(ToolModel.user_id == None).all()
714
- if user_id:
715
- results += session.query(ToolModel).filter(ToolModel.user_id == user_id).all()
714
+ # Query for public tools or user-specific tools
715
+ query = session.query(ToolModel).filter(or_(ToolModel.user_id == None, ToolModel.user_id == user_id))
716
+
717
+ # Apply cursor if provided (assuming cursor is an ID)
718
+ if cursor:
719
+ query = query.filter(ToolModel.id > cursor)
720
+
721
+ # Order by ID and apply limit
722
+ results = query.order_by(asc(ToolModel.id)).limit(limit).all()
723
+
724
+ # Convert to records
716
725
  res = [r.to_record() for r in results]
717
726
  return res
718
727
 
letta/schemas/memory.py CHANGED
@@ -9,6 +9,7 @@ if TYPE_CHECKING:
9
9
 
10
10
  from letta.schemas.block import Block
11
11
  from letta.schemas.message import Message
12
+ from letta.schemas.openai.chat_completion_request import Tool
12
13
 
13
14
 
14
15
  class ContextWindowOverview(BaseModel):
@@ -41,6 +42,9 @@ class ContextWindowOverview(BaseModel):
41
42
  num_tokens_summary_memory: int = Field(..., description="The number of tokens in the summary memory.")
42
43
  summary_memory: Optional[str] = Field(None, description="The content of the summary memory.")
43
44
 
45
+ num_tokens_functions_definitions: int = Field(..., description="The number of tokens in the functions definitions.")
46
+ functions_definitions: Optional[List[Tool]] = Field(..., description="The content of the functions definitions.")
47
+
44
48
  num_tokens_messages: int = Field(..., description="The number of tokens in the messages list.")
45
49
  # TODO make list of messages?
46
50
  # messages: List[dict] = Field(..., description="The messages in the context window.")
@@ -74,7 +74,7 @@ class ToolFunctionChoice(BaseModel):
74
74
  function: FunctionCall
75
75
 
76
76
 
77
- ToolChoice = Union[Literal["none", "auto"], ToolFunctionChoice]
77
+ ToolChoice = Union[Literal["none", "auto", "required"], ToolFunctionChoice]
78
78
 
79
79
 
80
80
  ## tools ##
@@ -117,7 +117,7 @@ class ChatCompletionRequest(BaseModel):
117
117
 
118
118
  # function-calling related
119
119
  tools: Optional[List[Tool]] = None
120
- tool_choice: Optional[ToolChoice] = "none"
120
+ tool_choice: Optional[ToolChoice] = None # "none" means don't call a tool
121
121
  # deprecated scheme
122
122
  functions: Optional[List[FunctionSchema]] = None
123
123
  function_call: Optional[FunctionCallChoice] = None
@@ -70,6 +70,7 @@ def create_application() -> "FastAPI":
70
70
  title="Letta",
71
71
  summary="Create LLM agents with long-term memory and custom tools 📚🦙",
72
72
  version="1.0.0", # TODO wire this up to the version in the package
73
+ debug=True,
73
74
  )
74
75
 
75
76
  if "--ade" in sys.argv:
@@ -27,6 +27,7 @@ from letta.schemas.memory import (
27
27
  from letta.schemas.message import Message, MessageCreate, UpdateMessage
28
28
  from letta.schemas.passage import Passage
29
29
  from letta.schemas.source import Source
30
+ from letta.schemas.tool import Tool
30
31
  from letta.server.rest_api.interface import StreamingServerInterface
31
32
  from letta.server.rest_api.utils import get_letta_server, sse_async_generator
32
33
  from letta.server.server import SyncServer
@@ -100,6 +101,17 @@ def update_agent(
100
101
  return server.update_agent(update_agent, user_id=actor.id)
101
102
 
102
103
 
104
+ @router.get("/{agent_id}/tools", response_model=List[Tool], operation_id="get_tools_from_agent")
105
+ def get_tools_from_agent(
106
+ agent_id: str,
107
+ server: "SyncServer" = Depends(get_letta_server),
108
+ user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
109
+ ):
110
+ """Get tools from an existing agent"""
111
+ actor = server.get_user_or_default(user_id=user_id)
112
+ return server.get_tools_from_agent(agent_id=agent_id, user_id=actor.id)
113
+
114
+
103
115
  @router.patch("/{agent_id}/add-tool/{tool_id}", response_model=AgentState, operation_id="add_tool_to_agent")
104
116
  def add_tool_to_agent(
105
117
  agent_id: str,
@@ -107,10 +119,8 @@ def add_tool_to_agent(
107
119
  server: "SyncServer" = Depends(get_letta_server),
108
120
  user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
109
121
  ):
110
- """Add tools to an exsiting agent"""
122
+ """Add tools to an existing agent"""
111
123
  actor = server.get_user_or_default(user_id=user_id)
112
-
113
- update_agent.id = agent_id
114
124
  return server.add_tool_to_agent(agent_id=agent_id, tool_id=tool_id, user_id=actor.id)
115
125
 
116
126
 
@@ -121,10 +131,8 @@ def remove_tool_from_agent(
121
131
  server: "SyncServer" = Depends(get_letta_server),
122
132
  user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
123
133
  ):
124
- """Add tools to an exsiting agent"""
134
+ """Add tools to an existing agent"""
125
135
  actor = server.get_user_or_default(user_id=user_id)
126
-
127
- update_agent.id = agent_id
128
136
  return server.remove_tool_from_agent(agent_id=agent_id, tool_id=tool_id, user_id=actor.id)
129
137
 
130
138
 
@@ -59,18 +59,21 @@ def get_tool_id(
59
59
 
60
60
  @router.get("/", response_model=List[Tool], operation_id="list_tools")
61
61
  def list_all_tools(
62
+ cursor: Optional[str] = None,
63
+ limit: Optional[int] = 50,
62
64
  server: SyncServer = Depends(get_letta_server),
63
65
  user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
64
66
  ):
65
67
  """
66
68
  Get a list of all tools available to agents created by a user
67
69
  """
68
- actor = server.get_user_or_default(user_id=user_id)
69
- actor.id
70
-
71
- # TODO: add back when user-specific
72
- return server.list_tools(user_id=actor.id)
73
- # return server.ms.list_tools(user_id=None)
70
+ try:
71
+ actor = server.get_user_or_default(user_id=user_id)
72
+ return server.list_tools(cursor=cursor, limit=limit, user_id=actor.id)
73
+ except Exception as e:
74
+ # Log or print the full exception here for debugging
75
+ print(f"Error occurred: {e}")
76
+ raise HTTPException(status_code=500, detail=str(e))
74
77
 
75
78
 
76
79
  @router.post("/", response_model=Tool, operation_id="create_tool")
letta/server/server.py CHANGED
@@ -73,7 +73,12 @@ from letta.schemas.file import FileMetadata
73
73
  from letta.schemas.job import Job
74
74
  from letta.schemas.letta_message import LettaMessage
75
75
  from letta.schemas.llm_config import LLMConfig
76
- from letta.schemas.memory import ArchivalMemorySummary, Memory, RecallMemorySummary
76
+ from letta.schemas.memory import (
77
+ ArchivalMemorySummary,
78
+ ContextWindowOverview,
79
+ Memory,
80
+ RecallMemorySummary,
81
+ )
77
82
  from letta.schemas.message import Message, MessageCreate, MessageRole, UpdateMessage
78
83
  from letta.schemas.organization import Organization, OrganizationCreate
79
84
  from letta.schemas.passage import Passage
@@ -977,13 +982,24 @@ class SyncServer(Server):
977
982
  # TODO: probably reload the agent somehow?
978
983
  return letta_agent.agent_state
979
984
 
985
+ def get_tools_from_agent(self, agent_id: str, user_id: Optional[str]) -> List[Tool]:
986
+ """Get tools from an existing agent"""
987
+ if self.ms.get_user(user_id=user_id) is None:
988
+ raise ValueError(f"User user_id={user_id} does not exist")
989
+ if self.ms.get_agent(agent_id=agent_id) is None:
990
+ raise ValueError(f"Agent agent_id={agent_id} does not exist")
991
+
992
+ # Get the agent object (loaded in memory)
993
+ letta_agent = self._get_or_load_agent(agent_id=agent_id)
994
+ return letta_agent.tools
995
+
980
996
  def add_tool_to_agent(
981
997
  self,
982
998
  agent_id: str,
983
999
  tool_id: str,
984
1000
  user_id: str,
985
1001
  ):
986
- """Update the agents core memory block, return the new state"""
1002
+ """Add tools from an existing agent"""
987
1003
  if self.ms.get_user(user_id=user_id) is None:
988
1004
  raise ValueError(f"User user_id={user_id} does not exist")
989
1005
  if self.ms.get_agent(agent_id=agent_id) is None:
@@ -1022,7 +1038,7 @@ class SyncServer(Server):
1022
1038
  tool_id: str,
1023
1039
  user_id: str,
1024
1040
  ):
1025
- """Update the agents core memory block, return the new state"""
1041
+ """Remove tools from an existing agent"""
1026
1042
  if self.ms.get_user(user_id=user_id) is None:
1027
1043
  raise ValueError(f"User user_id={user_id} does not exist")
1028
1044
  if self.ms.get_agent(agent_id=agent_id) is None:
@@ -1965,9 +1981,9 @@ class SyncServer(Server):
1965
1981
  """Delete a tool"""
1966
1982
  self.ms.delete_tool(tool_id)
1967
1983
 
1968
- def list_tools(self, user_id: str) -> List[Tool]:
1984
+ def list_tools(self, cursor: Optional[str] = None, limit: Optional[int] = 50, user_id: Optional[str] = None) -> List[Tool]:
1969
1985
  """List tools available to user_id"""
1970
- tools = self.ms.list_tools(user_id)
1986
+ tools = self.ms.list_tools(cursor=cursor, limit=limit, user_id=user_id)
1971
1987
  return tools
1972
1988
 
1973
1989
  def add_default_tools(self, module_name="base", user_id: Optional[str] = None):
@@ -2166,3 +2182,12 @@ class SyncServer(Server):
2166
2182
 
2167
2183
  def add_embedding_model(self, request: EmbeddingConfig) -> EmbeddingConfig:
2168
2184
  """Add a new embedding model"""
2185
+
2186
+ def get_agent_context_window(
2187
+ self,
2188
+ user_id: str,
2189
+ agent_id: str,
2190
+ ) -> ContextWindowOverview:
2191
+ # Get the current message
2192
+ letta_agent = self._get_or_load_agent(agent_id=agent_id)
2193
+ return letta_agent.get_context_window()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: letta-nightly
3
- Version: 0.5.0.dev20241018104142
3
+ Version: 0.5.0.dev20241019104023
4
4
  Summary: Create LLM agents with long-term memory and custom tools
5
5
  License: Apache License
6
6
  Author: Letta Team
@@ -24,7 +24,7 @@ Requires-Dist: alembic (>=1.13.3,<2.0.0)
24
24
  Requires-Dist: autoflake (>=2.3.0,<3.0.0) ; extra == "dev"
25
25
  Requires-Dist: black[jupyter] (>=24.2.0,<25.0.0) ; extra == "dev"
26
26
  Requires-Dist: chromadb (>=0.4.24,<0.5.0)
27
- Requires-Dist: composio-core (>=0.5.28,<0.6.0) ; extra == "external-tools"
27
+ Requires-Dist: composio-core (>=0.5.34,<0.6.0) ; extra == "external-tools"
28
28
  Requires-Dist: composio-langchain (>=0.5.28,<0.6.0) ; extra == "external-tools"
29
29
  Requires-Dist: crewai (>=0.41.1,<0.42.0) ; extra == "external-tools"
30
30
  Requires-Dist: crewai-tools (>=0.8.3,<0.9.0) ; extra == "external-tools"
@@ -1,6 +1,6 @@
1
1
  letta/__init__.py,sha256=cwav47GUQB8F9w0sHIDPe1nZMf_WL00KovBa9dZvSj4,996
2
2
  letta/__main__.py,sha256=6Hs2PV7EYc5Tid4g4OtcLXhqVHiNYTGzSBdoOnW2HXA,29
3
- letta/agent.py,sha256=picvtyzJzR0m60LTyvya99WnGEjePbeh1bgRqOo-Vng,71667
3
+ letta/agent.py,sha256=bXs6gulZAriEa8Bs9bLguN-T5hGUYe0h8FDPBl6Oz7U,72880
4
4
  letta/agent_store/chroma.py,sha256=upR5zGnGs6I6btulEYbiZdGG87BgKjxUJOQZ4Y-RQ_M,12492
5
5
  letta/agent_store/db.py,sha256=54EpxQYX0lAWxrsO0iUKw2vibF8-62Khczns2vxIK-0,23307
6
6
  letta/agent_store/lancedb.py,sha256=i63d4VZwj9UIOTNs5f0JZ_r5yZD-jKWz4FAH4RMpXOE,5104
@@ -15,7 +15,7 @@ letta/cli/cli_config.py,sha256=G7QqPNTtlQ4TdrXZrrFFGblZEhnkyrqN1Cl5z415C-g,8689
15
15
  letta/cli/cli_load.py,sha256=x4L8s15GwIW13xrhKYFWHo_y-IVGtoPDHWWKcHDRP10,4587
16
16
  letta/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  letta/client/admin.py,sha256=itdH1dGL143Je5tkZl8dQ1PavjepClar3QasxpbX1cI,7397
18
- letta/client/client.py,sha256=GJYPBYWf2Ufchl1V-XUy8uMkRQBH52lvl4_E7dFOPLM,91720
18
+ letta/client/client.py,sha256=Alx_m9b4ZX_A3G7XtOa5Lgbxtf9PmDhCkUf3QDK0jS0,93065
19
19
  letta/client/streaming.py,sha256=bfWlUu7z7EoPfKxBqIarYxGKyrL7Pj79BlliToqcCgI,4592
20
20
  letta/client/utils.py,sha256=OJlAKWrldc4I6M1WpcTWNtPJ4wfxlzlZqWLfCozkFtI,2872
21
21
  letta/config.py,sha256=j2I90fOh9d9__kOYObwTDLbvVwYR50rIql5nzrvREKg,19161
@@ -44,7 +44,7 @@ letta/llm_api/google_ai.py,sha256=3xZ074nSOCC22c15yerA5ngWzh0ex4wxeI-6faNbHPE,17
44
44
  letta/llm_api/helpers.py,sha256=8aG6LzB0T3NFlnab-RR2tj0ARUTMBHSd0icCur5-RCk,8813
45
45
  letta/llm_api/llm_api_tools.py,sha256=GEBO7Dlt7xtAQud1sVsigKZKPpLOZOt2IWL8LwcNV4o,14869
46
46
  letta/llm_api/mistral.py,sha256=fHdfD9ug-rQIk2qn8tRKay1U6w9maF11ryhKi91FfXM,1593
47
- letta/llm_api/openai.py,sha256=OidkR0VFXzwNW13EUlXbHWWw2ARZHfVDHWn59aEgwbo,21683
47
+ letta/llm_api/openai.py,sha256=er_cmGWeiMQsfFEXzG0DZhn8-Ftkh2q3nxtszXYRsbw,22195
48
48
  letta/local_llm/README.md,sha256=hFJyw5B0TU2jrh9nb0zGZMgdH-Ei1dSRfhvPQG_NSoU,168
49
49
  letta/local_llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  letta/local_llm/chat_completion_proxy.py,sha256=SiohxsjGTku4vOryOZx7I0t0xoO_sUuhXgoe62fKq3c,12995
@@ -76,7 +76,7 @@ letta/local_llm/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
76
76
  letta/local_llm/settings/deterministic_mirostat.py,sha256=kgRikcxYHfIbPFydHW6W7IO9jmp6NeA7JNAhnI3DPsc,1221
77
77
  letta/local_llm/settings/settings.py,sha256=ZAbzDpu2WsBXjVGXJ-TKUpS99VTI__3EoZml9KqYef0,2971
78
78
  letta/local_llm/settings/simple.py,sha256=HAO2jBJ_hJCEsXWIJcD0sckR0tI0zs3x2CPdf6ORQLs,719
79
- letta/local_llm/utils.py,sha256=DTv8S0lIpFBZlY6fjprtAU3n06eOPDKT6EXwnOgexLo,11363
79
+ letta/local_llm/utils.py,sha256=fDBoEGKc1SdhbvwqkQ6hRk2I7VCW3Rzurq81QdbCb7s,12174
80
80
  letta/local_llm/vllm/api.py,sha256=2kAGZjc_GH9ILJnVRq-45yfsfKELVfbC9VEl_cIC6vg,2590
81
81
  letta/local_llm/webui/api.py,sha256=kkxncdCFq1vjgvaHOoQ__j7rcDPgC1F64KcEm94Y6Rs,2639
82
82
  letta/local_llm/webui/legacy_api.py,sha256=k3H3y4qp2Fs-XmP24iSIEyvq6wjWFWBzklY3-wRAJNI,2335
@@ -85,7 +85,7 @@ letta/local_llm/webui/settings.py,sha256=gmLHfiOl1u4JmlAZU2d2O8YKF9lafdakyjwR_ft
85
85
  letta/log.py,sha256=QHquDnL7oUAvdKlAwUlCK9zXKDMUjrU9WA0bxnMsP0Y,2101
86
86
  letta/main.py,sha256=yHgM1lltQZvbE8k0QDQMmVyJiWEj07ZTOYIBHDxE_DQ,18709
87
87
  letta/memory.py,sha256=6q1x3-PY-PeXzAt6hvP-UF1ajvroPZ7XW-5nLy-JhMo,17657
88
- letta/metadata.py,sha256=gjwSD3TzhRUD-IFilbzHKjAhnEC2l7MeHF_31W9LEBw,36929
88
+ letta/metadata.py,sha256=HIzNn9A28iD3d5Utrey8Z8CQ4KHmaD1iib2a_blLvds,37174
89
89
  letta/o1_agent.py,sha256=0jospImZUKhuQZ0cop0INj8xI6cxhxNffGA8iloHyfU,3114
90
90
  letta/openai_backcompat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
91
  letta/openai_backcompat/openai_object.py,sha256=Y1ZS1sATP60qxJiOsjOP3NbwSzuzvkNAvb3DeuhM5Uk,13490
@@ -127,9 +127,9 @@ letta/schemas/letta_message.py,sha256=Slgxa59qZfdvqXuCVHOt03u-7JL456ZY-WLaK5UYYK
127
127
  letta/schemas/letta_request.py,sha256=_oiDshc_AoFWIfXRk2VX5-AxO5vDlyN-9r-gnyLj_30,1890
128
128
  letta/schemas/letta_response.py,sha256=_UJoO3UtC3F5DtQCHzdiGM1SHNPYPKvopIWqg8t5YZw,1564
129
129
  letta/schemas/llm_config.py,sha256=eFA48vKBTO70qaob8pak2CWOH7TCQeqWuClkMBc2vbY,4172
130
- letta/schemas/memory.py,sha256=COVipr9VPqbIz4QQ9kdlrylgVMx37odc0Sctjt4IZb4,11348
130
+ letta/schemas/memory.py,sha256=rBbfCps6Oi1p3eYDx8_bY34PQGXx69-pha0Uj4B9678,11650
131
131
  letta/schemas/message.py,sha256=X0adFviO6sbobFns30M0Ym6DChRDVThaA82gqbzw3Jg,33531
132
- letta/schemas/openai/chat_completion_request.py,sha256=Fa7xnSnG7WUQounJhnDu0fTSxoR6xOAh2bODuqmfypI,3345
132
+ letta/schemas/openai/chat_completion_request.py,sha256=AOIwgbN3CZKVqkuXeMHeSa53u4h0wVq69t3T_LJ0vIE,3389
133
133
  letta/schemas/openai/chat_completion_response.py,sha256=05FRfm1EsVivyeWo2aoJk34h3W4pAb4lBCPn1eujjcw,3916
134
134
  letta/schemas/openai/chat_completions.py,sha256=V0ZPIIk-ds3O6MAkNHMz8zh1hqMFSPrTcYr88WDYzWE,3588
135
135
  letta/schemas/openai/embedding_response.py,sha256=WKIZpXab1Av7v6sxKG8feW3ZtpQUNosmLVSuhXYa_xU,357
@@ -147,7 +147,7 @@ letta/server/rest_api/admin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
147
147
  letta/server/rest_api/admin/agents.py,sha256=cFNDU4Z8wGpcWXuo5aBgX6CcxLzPpTFYnTIaiF-3qvw,564
148
148
  letta/server/rest_api/admin/tools.py,sha256=HdXR_MRWkh3zMtb96Eaomp4rReNm3DirnXCNqAD7tNU,3093
149
149
  letta/server/rest_api/admin/users.py,sha256=IIec8G2yxVZtSo8dYrQPktVj8XIsZMptxigxmgULKO8,3480
150
- letta/server/rest_api/app.py,sha256=EJD3eGBAr_u6S7Ohjwrw6XuxKhci0tD-Wf5ccU_QDl8,6187
150
+ letta/server/rest_api/app.py,sha256=JNmDnvp9fP--hJPtPpEWgQT-14O1YOceZbWELr2vedA,6207
151
151
  letta/server/rest_api/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
152
152
  letta/server/rest_api/auth/index.py,sha256=fQBGyVylGSRfEMLQ17cZzrHd5Y1xiVylvPqH5Rl-lXQ,1378
153
153
  letta/server/rest_api/auth_token.py,sha256=725EFEIiNj4dh70hrSd94UysmFD8vcJLrTRfNHkzxDo,774
@@ -161,18 +161,18 @@ letta/server/rest_api/routers/openai/assistants/threads.py,sha256=WXVGBaBvSNPB7Z
161
161
  letta/server/rest_api/routers/openai/chat_completions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
162
162
  letta/server/rest_api/routers/openai/chat_completions/chat_completions.py,sha256=-uye6cm4SnoQGwxhr1N1FrSXOlnO2Hvbfj6k8JSc45k,4918
163
163
  letta/server/rest_api/routers/v1/__init__.py,sha256=sqlVZa-u9DJwdRsp0_8YUGrac9DHguIB4wETlEDRylA,666
164
- letta/server/rest_api/routers/v1/agents.py,sha256=beY1D78uIK9Dk_A6BdPiHtXFAoZh8Th3jEekR1MxsSk,24595
164
+ letta/server/rest_api/routers/v1/agents.py,sha256=Yoktva6_pSCRztUdZNZXdbnrp9L5OKnP5E1mZkbUAGw,25066
165
165
  letta/server/rest_api/routers/v1/blocks.py,sha256=0WekE_yBD2U3jYgPxI0DCFjACWavCAlvm_Ybw5SZBnw,2583
166
166
  letta/server/rest_api/routers/v1/health.py,sha256=pKCuVESlVOhGIb4VC4K-H82eZqfghmT6kvj2iOkkKuc,401
167
167
  letta/server/rest_api/routers/v1/jobs.py,sha256=a-j0v-5A0un0pVCOHpfeWnzpOWkVDQO6ti42k_qAlZY,2272
168
168
  letta/server/rest_api/routers/v1/llms.py,sha256=TcyvSx6MEM3je5F4DysL7ligmssL_pFlJaaO4uL95VY,877
169
169
  letta/server/rest_api/routers/v1/organizations.py,sha256=i3S9E1hu2Zj9g0pRv6wnQhz1VJ_RMIHCrGzgwY-Wj3Y,1945
170
170
  letta/server/rest_api/routers/v1/sources.py,sha256=eY_pk9jRL2Y9yIZdsTjH6EuKsfH1neaTU15MKNL0dvw,8749
171
- letta/server/rest_api/routers/v1/tools.py,sha256=YiGlgAaV1p0sbrf-Z7ZR6mQ4HZlKWN9KKcu53TBM1O0,3471
171
+ letta/server/rest_api/routers/v1/tools.py,sha256=vxE4b5juoiBiNWmplktuv6GEgenCkKBRov-t6usUJ9A,3665
172
172
  letta/server/rest_api/routers/v1/users.py,sha256=Y2rDvHOG1B5FLSOjutY3R22vt48IngbZ-9h8CohG5rc,3378
173
173
  letta/server/rest_api/static_files.py,sha256=NG8sN4Z5EJ8JVQdj19tkFa9iQ1kBPTab9f_CUxd_u4Q,3143
174
174
  letta/server/rest_api/utils.py,sha256=Fc2ZGKzLaBa2sEtSTVjJ8D5M0xIwsWC0CVAOIJaD3rY,2176
175
- letta/server/server.py,sha256=pAeqAr8zua7-j765M1oZECYgXLe5DnFdVf3QxYiaDuc,90569
175
+ letta/server/server.py,sha256=fEPkRE1R1jBu6S_pMYi2NmoTOkDwa6NjOnNnJVmm5Cw,91491
176
176
  letta/server/startup.sh,sha256=jeGV7B_PS0hS-tT6o6GpACrUbV9WV1NI2L9aLoUDDtc,311
177
177
  letta/server/static_files/assets/index-3ab03d5b.css,sha256=OrA9W4iKJ5h2Wlr7GwdAT4wow0CM8hVit1yOxEL49Qw,54295
178
178
  letta/server/static_files/assets/index-d6b3669a.js,sha256=i1nHReU0RPnj-a5W0nNPV4Y9bQ0FOW0ztjMz8a2AE-Y,1821560
@@ -189,8 +189,8 @@ letta/settings.py,sha256=gNdH-Ty6f-Nfz2j9ZMZFRQHac2KzgsxLZNt5l_TiAyo,3301
189
189
  letta/streaming_interface.py,sha256=_FPUWy58j50evHcpXyd7zB1wWqeCc71NCFeWh_TBvnw,15736
190
190
  letta/system.py,sha256=buKYPqG5n2x41hVmWpu6JUpyd7vTWED9Km2_M7dLrvk,6960
191
191
  letta/utils.py,sha256=neUs7mxNfndzRL5XUxerr8Lic6w7qnyyvf8FBwMnyWw,30852
192
- letta_nightly-0.5.0.dev20241018104142.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
193
- letta_nightly-0.5.0.dev20241018104142.dist-info/METADATA,sha256=yqSwuKHeE1WBG6rkRtmAwq6mXiGEpkiWpLg8aXVX-5g,10620
194
- letta_nightly-0.5.0.dev20241018104142.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
195
- letta_nightly-0.5.0.dev20241018104142.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
196
- letta_nightly-0.5.0.dev20241018104142.dist-info/RECORD,,
192
+ letta_nightly-0.5.0.dev20241019104023.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
193
+ letta_nightly-0.5.0.dev20241019104023.dist-info/METADATA,sha256=NO5Tf5FycuYWmQyKH0UcDvJ7IzdbJcjl50nUu0W6hBQ,10620
194
+ letta_nightly-0.5.0.dev20241019104023.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
195
+ letta_nightly-0.5.0.dev20241019104023.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
196
+ letta_nightly-0.5.0.dev20241019104023.dist-info/RECORD,,