letta-nightly 0.5.0.dev20241018104142__py3-none-any.whl → 0.5.0.dev20241020104030__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,
@@ -500,7 +503,7 @@ class Agent(BaseAgent):
500
503
  def _handle_ai_response(
501
504
  self,
502
505
  response_message: ChatCompletionMessage, # TODO should we eventually move the Message creation outside of this function?
503
- override_tool_call_id: bool = True,
506
+ override_tool_call_id: bool = False,
504
507
  # If we are streaming, we needed to create a Message ID ahead of time,
505
508
  # and now we want to use it in the creation of the Message object
506
509
  # TODO figure out a cleaner way to do this
@@ -527,6 +530,7 @@ class Agent(BaseAgent):
527
530
 
528
531
  # generate UUID for tool call
529
532
  if override_tool_call_id or response_message.function_call:
533
+ warnings.warn("Overriding the tool call can result in inconsistent tool call IDs during streaming")
530
534
  tool_call_id = get_tool_call_id() # needs to be a string for JSON
531
535
  response_message.tool_calls[0].id = tool_call_id
532
536
  else:
@@ -1458,6 +1462,24 @@ class Agent(BaseAgent):
1458
1462
  )
1459
1463
  num_tokens_external_memory_summary = count_tokens(external_memory_summary)
1460
1464
 
1465
+ # tokens taken up by function definitions
1466
+ if self.functions:
1467
+ available_functions_definitions = [ChatCompletionRequestTool(type="function", function=f) for f in self.functions]
1468
+ num_tokens_available_functions_definitions = num_tokens_from_functions(functions=self.functions, model=self.model)
1469
+ else:
1470
+ available_functions_definitions = []
1471
+ num_tokens_available_functions_definitions = 0
1472
+
1473
+ num_tokens_used_total = (
1474
+ num_tokens_system # system prompt
1475
+ + num_tokens_available_functions_definitions # function definitions
1476
+ + num_tokens_core_memory # core memory
1477
+ + num_tokens_external_memory_summary # metadata (statistics) about recall/archival
1478
+ + num_tokens_summary_memory # summary of ongoing conversation
1479
+ + num_tokens_messages # tokens taken by messages
1480
+ )
1481
+ assert isinstance(num_tokens_used_total, int)
1482
+
1461
1483
  return ContextWindowOverview(
1462
1484
  # context window breakdown (in messages)
1463
1485
  num_messages=len(self._messages),
@@ -1466,7 +1488,7 @@ class Agent(BaseAgent):
1466
1488
  num_tokens_external_memory_summary=num_tokens_external_memory_summary,
1467
1489
  # top-level information
1468
1490
  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,
1491
+ context_window_size_current=num_tokens_used_total,
1470
1492
  # context window breakdown (in tokens)
1471
1493
  num_tokens_system=num_tokens_system,
1472
1494
  system_prompt=system_prompt,
@@ -1476,6 +1498,9 @@ class Agent(BaseAgent):
1476
1498
  summary_memory=summary_memory,
1477
1499
  num_tokens_messages=num_tokens_messages,
1478
1500
  messages=self._messages,
1501
+ # related to functions
1502
+ num_tokens_functions_definitions=num_tokens_available_functions_definitions,
1503
+ functions_definitions=available_functions_definitions,
1479
1504
  )
1480
1505
 
1481
1506
 
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 (
@@ -36,7 +41,7 @@ from letta.streaming_interface import (
36
41
  AgentChunkStreamingInterface,
37
42
  AgentRefreshStreamingInterface,
38
43
  )
39
- from letta.utils import smart_urljoin
44
+ from letta.utils import get_tool_call_id, smart_urljoin
40
45
 
41
46
  OPENAI_SSE_DONE = "[DONE]"
42
47
 
@@ -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
  )
@@ -163,6 +174,7 @@ def openai_chat_completions_process_stream(
163
174
  stream_interface: Optional[Union[AgentChunkStreamingInterface, AgentRefreshStreamingInterface]] = None,
164
175
  create_message_id: bool = True,
165
176
  create_message_datetime: bool = True,
177
+ override_tool_call_id: bool = True,
166
178
  ) -> ChatCompletionResponse:
167
179
  """Process a streaming completion response, and return a ChatCompletionRequest at the end.
168
180
 
@@ -233,6 +245,14 @@ def openai_chat_completions_process_stream(
233
245
  ):
234
246
  assert isinstance(chat_completion_chunk, ChatCompletionChunkResponse), type(chat_completion_chunk)
235
247
 
248
+ # NOTE: this assumes that the tool call ID will only appear in one of the chunks during the stream
249
+ if override_tool_call_id:
250
+ for choice in chat_completion_chunk.choices:
251
+ if choice.delta.tool_calls and len(choice.delta.tool_calls) > 0:
252
+ for tool_call in choice.delta.tool_calls:
253
+ if tool_call.id is not None:
254
+ tool_call.id = get_tool_call_id()
255
+
236
256
  if stream_interface:
237
257
  if isinstance(stream_interface, AgentChunkStreamingInterface):
238
258
  stream_interface.process_chunk(
@@ -279,6 +299,7 @@ def openai_chat_completions_process_stream(
279
299
  else:
280
300
  accum_message.content += content_delta
281
301
 
302
+ # TODO(charles) make sure this works for parallel tool calling?
282
303
  if message_delta.tool_calls is not None:
283
304
  tool_calls_delta = message_delta.tool_calls
284
305
 
@@ -329,7 +350,7 @@ def openai_chat_completions_process_stream(
329
350
  assert all([c.finish_reason != TEMP_STREAM_FINISH_REASON for c in chat_completion_response.choices])
330
351
  assert all(
331
352
  [
332
- all([tc != TEMP_STREAM_TOOL_CALL_ID for tc in c.message.tool_calls]) if c.message.tool_calls else True
353
+ all([tc.id != TEMP_STREAM_TOOL_CALL_ID for tc in c.message.tool_calls]) if c.message.tool_calls else True
333
354
  for c in chat_completion_response.choices
334
355
  ]
335
356
  )
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
 
@@ -78,12 +78,14 @@ class FunctionCall(BaseModel):
78
78
 
79
79
  name: str
80
80
  arguments: str
81
+ function_call_id: str
81
82
 
82
83
 
83
84
  class FunctionCallDelta(BaseModel):
84
85
 
85
86
  name: Optional[str]
86
87
  arguments: Optional[str]
88
+ function_call_id: Optional[str]
87
89
 
88
90
  # NOTE: this is a workaround to exclude None values from the JSON dump,
89
91
  # since the OpenAI style of returning chunks doesn't include keys with null values
@@ -129,10 +131,10 @@ class FunctionCallMessage(LettaMessage):
129
131
  @classmethod
130
132
  def validate_function_call(cls, v):
131
133
  if isinstance(v, dict):
132
- if "name" in v and "arguments" in v:
133
- return FunctionCall(name=v["name"], arguments=v["arguments"])
134
- elif "name" in v or "arguments" in v:
135
- return FunctionCallDelta(name=v.get("name"), arguments=v.get("arguments"))
134
+ if "name" in v and "arguments" in v and "function_call_id" in v:
135
+ return FunctionCall(name=v["name"], arguments=v["arguments"], function_call_id=v["function_call_id"])
136
+ elif "name" in v or "arguments" in v or "function_call_id" in v:
137
+ return FunctionCallDelta(name=v.get("name"), arguments=v.get("arguments"), function_call_id=v.get("function_call_id"))
136
138
  else:
137
139
  raise ValueError("function_call must contain either 'name' or 'arguments'")
138
140
  return v
@@ -147,11 +149,13 @@ class FunctionReturn(LettaMessage):
147
149
  status (Literal["success", "error"]): The status of the function call
148
150
  id (str): The ID of the message
149
151
  date (datetime): The date the message was created in ISO format
152
+ function_call_id (str): A unique identifier for the function call that generated this message
150
153
  """
151
154
 
152
155
  message_type: Literal["function_return"] = "function_return"
153
156
  function_return: str
154
157
  status: Literal["success", "error"]
158
+ function_call_id: str
155
159
 
156
160
 
157
161
  # Legacy Letta API had an additional type "assistant_message" and the "function_call" was a formatted string
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.")
letta/schemas/message.py CHANGED
@@ -178,6 +178,7 @@ class Message(BaseMessage):
178
178
  function_call=FunctionCall(
179
179
  name=tool_call.function.name,
180
180
  arguments=tool_call.function.arguments,
181
+ function_call_id=tool_call.id,
181
182
  ),
182
183
  )
183
184
  )
@@ -203,6 +204,7 @@ class Message(BaseMessage):
203
204
  raise ValueError(f"Invalid status: {status}")
204
205
  except json.JSONDecodeError:
205
206
  raise ValueError(f"Failed to decode function return: {self.text}")
207
+ assert self.tool_call_id is not None
206
208
  messages.append(
207
209
  # TODO make sure this is what the API returns
208
210
  # function_return may not match exactly...
@@ -211,6 +213,7 @@ class Message(BaseMessage):
211
213
  date=self.created_at,
212
214
  function_return=self.text,
213
215
  status=status_enum,
216
+ function_call_id=self.tool_call_id,
214
217
  )
215
218
  )
216
219
  elif self.role == MessageRole.user:
@@ -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:
@@ -531,7 +531,11 @@ class StreamingServerInterface(AgentChunkStreamingInterface):
531
531
  processed_chunk = FunctionCallMessage(
532
532
  id=message_id,
533
533
  date=message_date,
534
- function_call=FunctionCallDelta(name=tool_call_delta.get("name"), arguments=tool_call_delta.get("arguments")),
534
+ function_call=FunctionCallDelta(
535
+ name=tool_call_delta.get("name"),
536
+ arguments=tool_call_delta.get("arguments"),
537
+ function_call_id=tool_call_delta.get("id"),
538
+ ),
535
539
  )
536
540
 
537
541
  else:
@@ -548,7 +552,11 @@ class StreamingServerInterface(AgentChunkStreamingInterface):
548
552
  processed_chunk = FunctionCallMessage(
549
553
  id=message_id,
550
554
  date=message_date,
551
- function_call=FunctionCallDelta(name=tool_call_delta.get("name"), arguments=tool_call_delta.get("arguments")),
555
+ function_call=FunctionCallDelta(
556
+ name=tool_call_delta.get("name"),
557
+ arguments=tool_call_delta.get("arguments"),
558
+ function_call_id=tool_call_delta.get("id"),
559
+ ),
552
560
  )
553
561
 
554
562
  elif choice.finish_reason is not None:
@@ -759,6 +767,7 @@ class StreamingServerInterface(AgentChunkStreamingInterface):
759
767
  function_call=FunctionCall(
760
768
  name=function_call.function.name,
761
769
  arguments=function_call.function.arguments,
770
+ function_call_id=function_call.id,
762
771
  ),
763
772
  )
764
773
 
@@ -786,21 +795,25 @@ class StreamingServerInterface(AgentChunkStreamingInterface):
786
795
  elif msg.startswith("Success: "):
787
796
  msg = msg.replace("Success: ", "")
788
797
  # new_message = {"function_return": msg, "status": "success"}
798
+ assert msg_obj.tool_call_id is not None
789
799
  new_message = FunctionReturn(
790
800
  id=msg_obj.id,
791
801
  date=msg_obj.created_at,
792
802
  function_return=msg,
793
803
  status="success",
804
+ function_call_id=msg_obj.tool_call_id,
794
805
  )
795
806
 
796
807
  elif msg.startswith("Error: "):
797
808
  msg = msg.replace("Error: ", "")
798
809
  # new_message = {"function_return": msg, "status": "error"}
810
+ assert msg_obj.tool_call_id is not None
799
811
  new_message = FunctionReturn(
800
812
  id=msg_obj.id,
801
813
  date=msg_obj.created_at,
802
814
  function_return=msg,
803
815
  status="error",
816
+ function_call_id=msg_obj.tool_call_id,
804
817
  )
805
818
 
806
819
  else:
@@ -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()
letta/utils.py CHANGED
@@ -488,6 +488,9 @@ def is_utc_datetime(dt: datetime) -> bool:
488
488
 
489
489
 
490
490
  def get_tool_call_id() -> str:
491
+ # TODO(sarah) make this a slug-style string?
492
+ # e.g. OpenAI: "call_xlIfzR1HqAW7xJPa3ExJSg3C"
493
+ # or similar to agents: "call-xlIfzR1HqAW7xJPa3ExJSg3C"
491
494
  return str(uuid.uuid4())[:TOOL_CALL_ID_MAX_LEN]
492
495
 
493
496
 
@@ -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.dev20241020104030
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=PRMDj0vZu5TGj-k2apeWcWYzJnBR36prdMXTKWnRYc8,72997
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=faJLzgx94cxz32VSeSxLDHeeSiKkb5WCM3BA_MNylkI,22821
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
@@ -123,13 +123,13 @@ letta/schemas/file.py,sha256=Ns0V2Jp6_lmiCmLCnXsOAh_UNqTW-fstcLKjYI35VOA,1357
123
123
  letta/schemas/health.py,sha256=zT6mYovvD17iJRuu2rcaQQzbEEYrkwvAE9TB7iU824c,139
124
124
  letta/schemas/job.py,sha256=605TWjUdNy5Rgoc7en_DX3Giz-I7sVTXiSRZqxL__d8,1543
125
125
  letta/schemas/letta_base.py,sha256=4QXFgyjCHqIagi8B6_4nmqb9eoJ52Y6aCxBxQpGX48M,2832
126
- letta/schemas/letta_message.py,sha256=Slgxa59qZfdvqXuCVHOt03u-7JL456ZY-WLaK5UYYKU,6234
126
+ letta/schemas/letta_message.py,sha256=RuVVtwFbi85yP3dXQxowofQ6cI2cO_CdGtgpHGQzgHc,6563
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
131
- letta/schemas/message.py,sha256=X0adFviO6sbobFns30M0Ym6DChRDVThaA82gqbzw3Jg,33531
132
- letta/schemas/openai/chat_completion_request.py,sha256=Fa7xnSnG7WUQounJhnDu0fTSxoR6xOAh2bODuqmfypI,3345
130
+ letta/schemas/memory.py,sha256=rBbfCps6Oi1p3eYDx8_bY34PQGXx69-pha0Uj4B9678,11650
131
+ letta/schemas/message.py,sha256=DQxnRYrYgHXpTKfMzfS-bpCAe-BO_Rmcfc1Wf-4GHjw,33703
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,11 +147,11 @@ 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
154
- letta/server/rest_api/interface.py,sha256=s_XyR6SRU1F2KpKbjtnv9zPHyXKgXvY4_mn2KtlyAMc,35606
154
+ letta/server/rest_api/interface.py,sha256=Mub9iOQFJh9HSwbc5X6OwHCdtwJYCBzhOjpSx9c5Lss,36181
155
155
  letta/server/rest_api/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
156
156
  letta/server/rest_api/routers/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
157
157
  letta/server/rest_api/routers/openai/assistants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -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
@@ -188,9 +188,9 @@ letta/server/ws_api/server.py,sha256=C2Kv48PCwl46DQFb0ZP30s86KJLQ6dZk2AhWQEZn9pY
188
188
  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
- 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,,
191
+ letta/utils.py,sha256=SXLEYhyp3gHyIjrxNIKNZZ5ittKo3KOj6zxgC_Trex0,31012
192
+ letta_nightly-0.5.0.dev20241020104030.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
193
+ letta_nightly-0.5.0.dev20241020104030.dist-info/METADATA,sha256=zTuYCjElFDt7egZOIY1RzgElSPc3gyeJxRiAkKhj4SA,10620
194
+ letta_nightly-0.5.0.dev20241020104030.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
195
+ letta_nightly-0.5.0.dev20241020104030.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
196
+ letta_nightly-0.5.0.dev20241020104030.dist-info/RECORD,,