letta-nightly 0.6.7.dev20250108104013__py3-none-any.whl → 0.6.8.dev20250109011239__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 CHANGED
@@ -1,9 +1,9 @@
1
- __version__ = "0.6.7"
1
+ __version__ = "0.6.8"
2
2
 
3
3
  # import clients
4
4
  from letta.client.client import LocalClient, RESTClient, create_client
5
5
 
6
- # imports for easier access
6
+ # # imports for easier access
7
7
  from letta.schemas.agent import AgentState
8
8
  from letta.schemas.block import Block
9
9
  from letta.schemas.embedding_config import EmbeddingConfig
letta/agent.py CHANGED
@@ -1075,6 +1075,8 @@ def save_agent(agent: Agent):
1075
1075
  message_ids=agent_state.message_ids,
1076
1076
  description=agent_state.description,
1077
1077
  metadata_=agent_state.metadata_,
1078
+ # TODO: Add this back in later
1079
+ # tool_exec_environment_variables=agent_state.get_agent_env_vars_as_dict(),
1078
1080
  )
1079
1081
  agent_manager.update_agent(agent_id=agent_state.id, agent_update=update_agent, actor=agent.user)
1080
1082
 
letta/client/client.py CHANGED
@@ -35,7 +35,6 @@ from letta.schemas.source import Source, SourceCreate, SourceUpdate
35
35
  from letta.schemas.tool import Tool, ToolCreate, ToolUpdate
36
36
  from letta.schemas.tool_rule import BaseToolRule
37
37
  from letta.server.rest_api.interface import QueuingInterface
38
- from letta.server.server import SyncServer
39
38
  from letta.utils import get_human_text, get_persona_text
40
39
 
41
40
 
@@ -1031,9 +1030,10 @@ class RESTClient(AbstractClient):
1031
1030
  def create_block(
1032
1031
  self, label: str, value: str, limit: Optional[int] = None, template_name: Optional[str] = None, is_template: bool = False
1033
1032
  ) -> Block: #
1034
- request = CreateBlock(label=label, value=value, template=is_template, template_name=template_name)
1033
+ request_kwargs = dict(label=label, value=value, template=is_template, template_name=template_name)
1035
1034
  if limit:
1036
- request.limit = limit
1035
+ request_kwargs["limit"] = limit
1036
+ request = CreateBlock(**request_kwargs)
1037
1037
  response = requests.post(f"{self.base_url}/{self.api_prefix}/blocks", json=request.model_dump(), headers=self.headers)
1038
1038
  if response.status_code != 200:
1039
1039
  raise ValueError(f"Failed to create block: {response.text}")
@@ -2010,6 +2010,8 @@ class LocalClient(AbstractClient):
2010
2010
  debug (bool): Whether to print debug information.
2011
2011
  """
2012
2012
 
2013
+ from letta.server.server import SyncServer
2014
+
2013
2015
  # set logging levels
2014
2016
  letta.utils.DEBUG = debug
2015
2017
  logging.getLogger().setLevel(logging.CRITICAL)
letta/constants.py CHANGED
@@ -7,6 +7,8 @@ ADMIN_PREFIX = "/v1/admin"
7
7
  API_PREFIX = "/v1"
8
8
  OPENAI_API_PREFIX = "/openai"
9
9
 
10
+ COMPOSIO_ENTITY_ENV_VAR_KEY = "COMPOSIO_ENTITY"
11
+
10
12
  # String in the error message for when the context window is too large
11
13
  # Example full message:
12
14
  # This model's maximum context length is 8192 tokens. However, your messages resulted in 8198 tokens (7450 in the messages, 748 in the functions). Please reduce the length of the messages or functions.
@@ -1,8 +1,11 @@
1
1
  from typing import Any, Optional, Union
2
2
 
3
3
  import humps
4
+ from composio.constants import DEFAULT_ENTITY_ID
4
5
  from pydantic import BaseModel
5
6
 
7
+ from letta.constants import COMPOSIO_ENTITY_ENV_VAR_KEY
8
+
6
9
 
7
10
  def generate_composio_tool_wrapper(action_name: str) -> tuple[str, str]:
8
11
  # Instantiate the object
@@ -13,12 +16,16 @@ def generate_composio_tool_wrapper(action_name: str) -> tuple[str, str]:
13
16
 
14
17
  wrapper_function_str = f"""
15
18
  def {func_name}(**kwargs):
16
- from composio import Action, App, Tag
17
19
  from composio_langchain import ComposioToolSet
20
+ import os
21
+
22
+ entity_id = os.getenv('{COMPOSIO_ENTITY_ENV_VAR_KEY}', '{DEFAULT_ENTITY_ID}')
23
+ composio_toolset = ComposioToolSet(entity_id=entity_id)
24
+ response = composio_toolset.execute_action(action='{action_name}', params=kwargs)
18
25
 
19
- composio_toolset = ComposioToolSet()
20
- tool = {tool_instantiation_str}
21
- return tool.func(**kwargs)['data']
26
+ if response["error"]:
27
+ raise RuntimeError(response["error"])
28
+ return response["data"]
22
29
  """
23
30
 
24
31
  # Compile safety check
@@ -3,7 +3,6 @@ from typing import Any, Dict, List, Optional, Type, Union, get_args, get_origin
3
3
 
4
4
  from docstring_parser import parse
5
5
  from pydantic import BaseModel
6
- from pydantic.v1 import BaseModel as V1BaseModel
7
6
 
8
7
 
9
8
  def is_optional(annotation):
@@ -22,6 +22,7 @@ from letta.schemas.llm_config import LLMConfig
22
22
  from letta.schemas.message import Message
23
23
  from letta.schemas.openai.chat_completion_request import ChatCompletionRequest, Tool, cast_message_to_subtype
24
24
  from letta.schemas.openai.chat_completion_response import ChatCompletionResponse
25
+ from letta.services.provider_manager import ProviderManager
25
26
  from letta.settings import ModelSettings
26
27
  from letta.streaming_interface import AgentChunkStreamingInterface, AgentRefreshStreamingInterface
27
28
 
@@ -251,9 +252,12 @@ def create(
251
252
  tool_call = {"type": "function", "function": {"name": force_tool_call}}
252
253
  assert functions is not None
253
254
 
255
+ # load anthropic key from db in case a custom key has been stored
256
+ anthropic_key_override = ProviderManager().get_anthropic_key_override()
257
+
254
258
  return anthropic_chat_completions_request(
255
259
  url=llm_config.model_endpoint,
256
- api_key=model_settings.anthropic_api_key,
260
+ api_key=anthropic_key_override if anthropic_key_override else model_settings.anthropic_api_key,
257
261
  data=ChatCompletionRequest(
258
262
  model=llm_config.model,
259
263
  messages=[cast_message_to_subtype(m.to_openai_dict()) for m in messages],
letta/orm/__init__.py CHANGED
@@ -8,7 +8,8 @@ from letta.orm.job import Job
8
8
  from letta.orm.message import Message
9
9
  from letta.orm.organization import Organization
10
10
  from letta.orm.passage import AgentPassage, BasePassage, SourcePassage
11
- from letta.orm.sandbox_config import SandboxConfig, SandboxEnvironmentVariable
11
+ from letta.orm.provider import Provider
12
+ from letta.orm.sandbox_config import AgentEnvironmentVariable, SandboxConfig, SandboxEnvironmentVariable
12
13
  from letta.orm.source import Source
13
14
  from letta.orm.sources_agents import SourcesAgents
14
15
  from letta.orm.tool import Tool
letta/orm/organization.py CHANGED
@@ -9,6 +9,7 @@ if TYPE_CHECKING:
9
9
 
10
10
  from letta.orm.agent import Agent
11
11
  from letta.orm.file import FileMetadata
12
+ from letta.orm.provider import Provider
12
13
  from letta.orm.sandbox_config import AgentEnvironmentVariable
13
14
  from letta.orm.tool import Tool
14
15
  from letta.orm.user import User
@@ -45,6 +46,7 @@ class Organization(SqlalchemyBase):
45
46
  "SourcePassage", back_populates="organization", cascade="all, delete-orphan"
46
47
  )
47
48
  agent_passages: Mapped[List["AgentPassage"]] = relationship("AgentPassage", back_populates="organization", cascade="all, delete-orphan")
49
+ providers: Mapped[List["Provider"]] = relationship("Provider", back_populates="organization", cascade="all, delete-orphan")
48
50
 
49
51
  @property
50
52
  def passages(self) -> List[Union["SourcePassage", "AgentPassage"]]:
letta/orm/provider.py ADDED
@@ -0,0 +1,23 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
4
+
5
+ from letta.orm.mixins import OrganizationMixin
6
+ from letta.orm.sqlalchemy_base import SqlalchemyBase
7
+ from letta.providers import Provider as PydanticProvider
8
+
9
+ if TYPE_CHECKING:
10
+ from letta.orm.organization import Organization
11
+
12
+
13
+ class Provider(SqlalchemyBase, OrganizationMixin):
14
+ """Provider ORM class"""
15
+
16
+ __tablename__ = "providers"
17
+ __pydantic_model__ = PydanticProvider
18
+
19
+ name: Mapped[str] = mapped_column(nullable=False, doc="The name of the provider")
20
+ api_key: Mapped[str] = mapped_column(nullable=True, doc="API key used for requests to the provider.")
21
+
22
+ # relationships
23
+ organization: Mapped["Organization"] = relationship("Organization", back_populates="providers")
letta/providers.py CHANGED
@@ -1,16 +1,24 @@
1
1
  from typing import List, Optional
2
2
 
3
- from pydantic import BaseModel, Field, model_validator
3
+ from pydantic import Field, model_validator
4
4
 
5
5
  from letta.constants import LLM_MAX_TOKENS, MIN_CONTEXT_WINDOW
6
6
  from letta.llm_api.azure_openai import get_azure_chat_completions_endpoint, get_azure_embeddings_endpoint
7
7
  from letta.llm_api.azure_openai_constants import AZURE_MODEL_TO_CONTEXT_LENGTH
8
8
  from letta.schemas.embedding_config import EmbeddingConfig
9
+ from letta.schemas.letta_base import LettaBase
9
10
  from letta.schemas.llm_config import LLMConfig
11
+ from letta.services.organization_manager import OrganizationManager
10
12
 
11
13
 
12
- class Provider(BaseModel):
14
+ class ProviderBase(LettaBase):
15
+ __id_prefix__ = "provider"
16
+
17
+
18
+ class Provider(ProviderBase):
13
19
  name: str = Field(..., description="The name of the provider")
20
+ api_key: Optional[str] = Field(None, description="API key used for requests to the provider.")
21
+ organization_id: Optional[str] = Field(OrganizationManager.DEFAULT_ORG_ID, description="The organization id of the user")
14
22
 
15
23
  def list_llm_models(self) -> List[LLMConfig]:
16
24
  return []
@@ -29,6 +37,17 @@ class Provider(BaseModel):
29
37
  return f"{self.name}/{model_name}"
30
38
 
31
39
 
40
+ class ProviderCreate(ProviderBase):
41
+ name: str = Field(..., description="The name of the provider.")
42
+ api_key: str = Field(..., description="API key used for requests to the provider.")
43
+ organization_id: str = Field(..., description="The organization id that this provider information pertains to.")
44
+
45
+
46
+ class ProviderUpdate(ProviderBase):
47
+ id: str = Field(..., description="The id of the provider to update.")
48
+ api_key: str = Field(..., description="API key used for requests to the provider.")
49
+
50
+
32
51
  class LettaProvider(Provider):
33
52
 
34
53
  name: str = "letta"
letta/schemas/agent.py CHANGED
@@ -80,9 +80,16 @@ class AgentState(OrmMetadataBase, validate_assignment=True):
80
80
  sources: List[Source] = Field(..., description="The sources used by the agent.")
81
81
  tags: List[str] = Field(..., description="The tags associated with the agent.")
82
82
  tool_exec_environment_variables: List[AgentEnvironmentVariable] = Field(
83
- ..., description="The environment variables for tool execution specific to this agent."
83
+ default_factory=list, description="The environment variables for tool execution specific to this agent."
84
84
  )
85
85
 
86
+ def get_agent_env_vars_as_dict(self) -> Dict[str, str]:
87
+ # Get environment variables for this agent specifically
88
+ per_agent_env_vars = {}
89
+ for agent_env_var_obj in self.tool_exec_environment_variables:
90
+ per_agent_env_vars[agent_env_var_obj.key] = agent_env_var_obj.value
91
+ return per_agent_env_vars
92
+
86
93
 
87
94
  class CreateAgent(BaseModel, validate_assignment=True): #
88
95
  # all optional as server can generate defaults
@@ -127,6 +134,7 @@ class CreateAgent(BaseModel, validate_assignment=True): #
127
134
  tool_exec_environment_variables: Optional[Dict[str, str]] = Field(
128
135
  None, description="The environment variables for tool execution specific to this agent."
129
136
  )
137
+ variables: Optional[Dict[str, str]] = Field(None, description="The variables that should be set for the agent.")
130
138
 
131
139
  @field_validator("name")
132
140
  @classmethod
@@ -11,6 +11,10 @@ class LettaRequest(BaseModel):
11
11
 
12
12
  # Flags to support the use of AssistantMessage message types
13
13
 
14
+ use_assistant_message: bool = Field(
15
+ default=True,
16
+ description="Whether the server should parse specific tool call arguments (default `send_message`) as `AssistantMessage` objects.",
17
+ )
14
18
  assistant_message_tool_name: str = Field(
15
19
  default=DEFAULT_MESSAGE_TOOL,
16
20
  description="The name of the designated message tool.",
@@ -46,6 +46,8 @@ def list_agents(
46
46
  ),
47
47
  server: "SyncServer" = Depends(get_letta_server),
48
48
  user_id: Optional[str] = Header(None, alias="user_id"),
49
+ cursor: Optional[int] = Query(None, description="Cursor for pagination"),
50
+ limit: Optional[int] = Query(None, description="Limit for pagination"),
49
51
  # Extract user_id from header, default to None if not present
50
52
  ):
51
53
  """
@@ -66,7 +68,7 @@ def list_agents(
66
68
  }
67
69
 
68
70
  # Call list_agents with the dynamic kwargs
69
- agents = server.agent_manager.list_agents(actor=actor, **kwargs)
71
+ agents = server.agent_manager.list_agents(actor=actor, cursor=cursor, limit=limit, **kwargs)
70
72
  return agents
71
73
 
72
74
 
@@ -491,6 +493,7 @@ async def send_message(
491
493
  stream_steps=False,
492
494
  stream_tokens=False,
493
495
  # Support for AssistantMessage
496
+ use_assistant_message=request.use_assistant_message,
494
497
  assistant_message_tool_name=request.assistant_message_tool_name,
495
498
  assistant_message_tool_kwarg=request.assistant_message_tool_kwarg,
496
499
  )
@@ -636,6 +639,7 @@ async def send_message_to_agent(
636
639
  chat_completion_mode: bool = False,
637
640
  timestamp: Optional[datetime] = None,
638
641
  # Support for AssistantMessage
642
+ use_assistant_message: bool = True,
639
643
  assistant_message_tool_name: str = DEFAULT_MESSAGE_TOOL,
640
644
  assistant_message_tool_kwarg: str = DEFAULT_MESSAGE_TOOL_KWARG,
641
645
  ) -> Union[StreamingResponse, LettaResponse]:
@@ -666,7 +670,7 @@ async def send_message_to_agent(
666
670
  stream_tokens = False
667
671
 
668
672
  # Create a new interface per request
669
- letta_agent.interface = StreamingServerInterface()
673
+ letta_agent.interface = StreamingServerInterface(use_assistant_message)
670
674
  streaming_interface = letta_agent.interface
671
675
  if not isinstance(streaming_interface, StreamingServerInterface):
672
676
  raise ValueError(f"Agent has wrong type of interface: {type(streaming_interface)}")
@@ -0,0 +1,72 @@
1
+ from fastapi import APIRouter, Depends
2
+
3
+ from letta.providers import Provider, ProviderCreate, ProviderUpdate
4
+ from letta.server.rest_api.utils import get_letta_server
5
+
6
+ if TYPE_CHECKING:
7
+ from letta.server.server import SyncServer
8
+
9
+ router = APIRouter(prefix="/providers", tags=["providers", "admin"])
10
+
11
+
12
+ @router.get("/", tags=["admin"], response_model=List[Provider], operation_id="list_providers")
13
+ def list_providers(
14
+ cursor: Optional[str] = Query(None),
15
+ limit: Optional[int] = Query(50),
16
+ server: "SyncServer" = Depends(get_letta_server),
17
+ ):
18
+ """
19
+ Get a list of all custom providers in the database
20
+ """
21
+ try:
22
+ providers = server.provider_manager.list_providers(cursor=cursor, limit=limit)
23
+ except HTTPException:
24
+ raise
25
+ except Exception as e:
26
+ raise HTTPException(status_code=500, detail=f"{e}")
27
+ return providers
28
+
29
+
30
+ @router.post("/", tags=["admin"], response_model=Provider, operation_id="create_provider")
31
+ def create_provider(
32
+ request: ProviderCreate = Body(...),
33
+ server: "SyncServer" = Depends(get_letta_server),
34
+ ):
35
+ """
36
+ Create a new custom provider
37
+ """
38
+ provider = Provider(**request.model_dump())
39
+ provider = server.provider_manager.create_provider(provider)
40
+ return provider
41
+
42
+
43
+ @router.put("/", tags=["admin"], response_model=Provider, operation_id="update_provider")
44
+ def update_provider(
45
+ request: ProviderUpdate = Body(...),
46
+ server: "SyncServer" = Depends(get_letta_server),
47
+ ):
48
+ """
49
+ Update an existing custom provider
50
+ """
51
+ provider = server.provider_manager.update_provider(request)
52
+ return provider
53
+
54
+
55
+ @router.delete("/", tags=["admin"], response_model=Provider, operation_id="delete_provider")
56
+ def delete_provider(
57
+ provider_id: str = Query(..., description="The provider_id key to be deleted."),
58
+ server: "SyncServer" = Depends(get_letta_server),
59
+ ):
60
+ """
61
+ Delete an existing custom provider
62
+ """
63
+ try:
64
+ provider = server.provider_manager.get_provider_by_id(provider_id=provider_id)
65
+ if provider is None:
66
+ raise HTTPException(status_code=404, detail=f"Provider does not exist")
67
+ server.provider_manager.delete_provider_by_id(provider_id=provider_id)
68
+ except HTTPException:
69
+ raise
70
+ except Exception as e:
71
+ raise HTTPException(status_code=500, detail=f"{e}")
72
+ return user
letta/server/server.py CHANGED
@@ -66,6 +66,7 @@ from letta.services.message_manager import MessageManager
66
66
  from letta.services.organization_manager import OrganizationManager
67
67
  from letta.services.passage_manager import PassageManager
68
68
  from letta.services.per_agent_lock_manager import PerAgentLockManager
69
+ from letta.services.provider_manager import ProviderManager
69
70
  from letta.services.sandbox_config_manager import SandboxConfigManager
70
71
  from letta.services.source_manager import SourceManager
71
72
  from letta.services.tool_execution_sandbox import ToolExecutionSandbox
@@ -180,6 +181,7 @@ def db_error_handler():
180
181
  exit(1)
181
182
 
182
183
 
184
+ print("Creating engine", settings.letta_pg_uri)
183
185
  if settings.letta_pg_uri_no_default:
184
186
  config.recall_storage_type = "postgres"
185
187
  config.recall_storage_uri = settings.letta_pg_uri_no_default
@@ -289,6 +291,7 @@ class SyncServer(Server):
289
291
  self.message_manager = MessageManager()
290
292
  self.job_manager = JobManager()
291
293
  self.agent_manager = AgentManager()
294
+ self.provider_manager = ProviderManager()
292
295
 
293
296
  # Managers that interface with parallelism
294
297
  self.per_agent_lock_manager = PerAgentLockManager()
@@ -1029,7 +1032,7 @@ class SyncServer(Server):
1029
1032
  """List available models"""
1030
1033
 
1031
1034
  llm_models = []
1032
- for provider in self._enabled_providers:
1035
+ for provider in self.get_enabled_providers():
1033
1036
  try:
1034
1037
  llm_models.extend(provider.list_llm_models())
1035
1038
  except Exception as e:
@@ -1039,13 +1042,19 @@ class SyncServer(Server):
1039
1042
  def list_embedding_models(self) -> List[EmbeddingConfig]:
1040
1043
  """List available embedding models"""
1041
1044
  embedding_models = []
1042
- for provider in self._enabled_providers:
1045
+ for provider in self.get_enabled_providers():
1043
1046
  try:
1044
1047
  embedding_models.extend(provider.list_embedding_models())
1045
1048
  except Exception as e:
1046
1049
  warnings.warn(f"An error occurred while listing embedding models for provider {provider}: {e}")
1047
1050
  return embedding_models
1048
1051
 
1052
+ def get_enabled_providers(self):
1053
+ providers_from_env = {p.name: p for p in self._enabled_providers}
1054
+ providers_from_db = {p.name: p for p in self.provider_manager.list_providers()}
1055
+ # Merge the two dictionaries, keeping the values from providers_from_db where conflicts occur
1056
+ return {**providers_from_env, **providers_from_db}.values()
1057
+
1049
1058
  def get_llm_config_from_handle(self, handle: str, context_window_limit: Optional[int] = None) -> LLMConfig:
1050
1059
  provider_name, model_name = handle.split("/", 1)
1051
1060
  provider = self.get_provider_from_name(provider_name)
@@ -1 +1 @@
1
- *,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}:root{--background: 210, 10%, 92%;--background-lighter: 0, 0%, 100%;--background-darker: 210, 6%, 86%;--foreground: 224 71.4% 4.1%;--card: 0 0% 100%;--card-foreground: 224 71.4% 4.1%;--popover: 0 0% 100%;--popover-foreground: 224 71.4% 4.1%;--primary: 220.9 39.3% 11%;--primary-foreground: 210 20% 98%;--secondary: 240, 92%, 35%;--secondary-foreground: 0, 0%, 100%;--muted: 220 14.3% 95.9%;--muted-foreground: 220 8.9% 46.1%;--accent: 220 14.3% 95.9%;--accent-foreground: 220.9 39.3% 11%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 210 20% 98%;--border: 210, 6%, 86%;--input: 210, 6%, 86%;--ring: 224 71.4% 4.1%;--radius: .5rem}.dark{--background: 224 71.4% 4.1%;--background-lighter: 224 71.4% 4.1%;--background-darker: 224 71.4% 4.1%;--foreground: 210 20% 98%;--card: 224 71.4% 4.1%;--card-foreground: 210 20% 98%;--popover: 224 71.4% 4.1%;--popover-foreground: 210 20% 98%;--primary: 210 20% 98%;--primary-foreground: 220.9 39.3% 11%;--secondary: 10, 100%, 60%;--secondary-foreground: 210 20% 98%;--muted: 215 27.9% 16.9%;--muted-foreground: 217.9 10.6% 64.9%;--accent: 215 27.9% 16.9%;--accent-foreground: 210 20% 98%;--destructive: 0 62.8% 30.6%;--destructive-foreground: 210 20% 98%;--border: 215 27.9% 16.9%;--input: 215 27.9% 16.9%;--ring: 216 12.2% 83.9%}*{border-color:hsl(var(--border))}html{height:100%}body{height:100%;width:100%;background-color:hsl(var(--background));color:hsl(var(--foreground));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}input::file-selector-button{color:hsl(var(--foreground))}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.fixed{position:fixed}.mt-10{margin-top:2.5rem}.mt-3{margin-top:.75rem}.flex{display:flex}.h-\[100dvh\]{height:100dvh}.h-full{height:100%}.w-\[100dvw\]{width:100dvw}.w-full{width:100%}.max-w-\[600px\]{max-width:600px}.max-w-\[893px\]{max-width:893px}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-5{gap:1.25rem}.border{border-width:1px}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.p-0{padding:0}.p-10{padding:2.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.PopoverContent{width:var(--radix-popover-trigger-width);max-height:var(--radix-popover-content-available-height)}
1
+ *,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}:root{--background: 210, 10%, 92%;--background-lighter: 0, 0%, 100%;--background-darker: 210, 6%, 86%;--foreground: 224 71.4% 4.1%;--card: 0 0% 100%;--card-foreground: 224 71.4% 4.1%;--popover: 0 0% 100%;--popover-foreground: 224 71.4% 4.1%;--brand: 220.9 39.3% 11%;--brand-foreground: 210 20% 98%;--primary: 240, 92%, 35%;--primary-foreground: 0, 0%, 100%;--muted: 220 14.3% 95.9%;--muted-foreground: 220 8.9% 46.1%;--accent: 220 14.3% 95.9%;--accent-foreground: 220.9 39.3% 11%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 210 20% 98%;--border: 210, 6%, 86%;--input: 210, 6%, 86%;--ring: 224 71.4% 4.1%;--radius: .5rem}.dark{--background: 224 71.4% 4.1%;--background-lighter: 224 71.4% 4.1%;--background-darker: 224 71.4% 4.1%;--foreground: 210 20% 98%;--card: 224 71.4% 4.1%;--card-foreground: 210 20% 98%;--popover: 224 71.4% 4.1%;--popover-foreground: 210 20% 98%;--brand: 210 20% 98%;--brand-foreground: 220.9 39.3% 11%;--primary: 10, 100%, 60%;--primary-foreground: 210 20% 98%;--muted: 215 27.9% 16.9%;--muted-foreground: 217.9 10.6% 64.9%;--accent: 215 27.9% 16.9%;--accent-foreground: 210 20% 98%;--destructive: 0 62.8% 30.6%;--destructive-foreground: 210 20% 98%;--border: 215 27.9% 16.9%;--input: 215 27.9% 16.9%;--ring: 216 12.2% 83.9%}*{border-color:hsl(var(--border))}html{height:100%}body{height:100%;width:100%;background-color:hsl(var(--background));color:hsl(var(--foreground));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}input::file-selector-button{color:hsl(var(--foreground))}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.fixed{position:fixed}.mt-10{margin-top:2.5rem}.mt-3{margin-top:.75rem}.flex{display:flex}.h-\[100dvh\]{height:100dvh}.h-full{height:100%}.w-\[100dvw\]{width:100dvw}.w-full{width:100%}.max-w-\[600px\]{max-width:600px}.max-w-\[893px\]{max-width:893px}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-5{gap:1.25rem}.border{border-width:1px}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.p-0{padding:0}.p-10{padding:2.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.PopoverContent{width:var(--radix-popover-trigger-width);max-height:var(--radix-popover-content-available-height)}
@@ -7,7 +7,7 @@
7
7
 
8
8
  <meta name="viewport" content="width=device-width, initial-scale=1" />
9
9
  <link rel="icon" type="image/x-icon" href="/favicon.ico" />
10
-
10
+
11
11
  <script>
12
12
  if (localStorage.theme === 'dark') {
13
13
  if (document && document.documentElement) {
@@ -34,6 +34,6 @@
34
34
  </head>
35
35
  <body>
36
36
  <div class="h-full w-full" id="root"></div>
37
-
37
+
38
38
  </body>
39
39
  </html>
@@ -338,11 +338,30 @@ class AgentManager:
338
338
  # Retrieve the agent
339
339
  agent = AgentModel.read(db_session=session, identifier=agent_id, actor=actor)
340
340
 
341
- # Replace the environment variables
342
- agent.tool_exec_environment_variables = [
343
- AgentEnvironmentVariableModel(key=key, value=value, agent_id=agent_id, organization_id=actor.organization_id)
344
- for key, value in env_vars.items()
345
- ]
341
+ # Fetch existing environment variables as a dictionary
342
+ existing_vars = {var.key: var for var in agent.tool_exec_environment_variables}
343
+
344
+ # Update or create environment variables
345
+ updated_vars = []
346
+ for key, value in env_vars.items():
347
+ if key in existing_vars:
348
+ # Update existing variable
349
+ existing_vars[key].value = value
350
+ updated_vars.append(existing_vars[key])
351
+ else:
352
+ # Create new variable
353
+ updated_vars.append(
354
+ AgentEnvironmentVariableModel(
355
+ key=key,
356
+ value=value,
357
+ agent_id=agent_id,
358
+ organization_id=actor.organization_id,
359
+ )
360
+ )
361
+
362
+ # Remove stale variables
363
+ stale_keys = set(existing_vars) - set(env_vars)
364
+ agent.tool_exec_environment_variables = [var for var in updated_vars if var.key not in stale_keys]
346
365
 
347
366
  # Update the agent in the database
348
367
  agent.update(session, actor=actor)
@@ -0,0 +1,63 @@
1
+ from typing import List, Optional
2
+
3
+ from letta.orm.provider import Provider as ProviderModel
4
+ from letta.providers import Provider as PydanticProvider
5
+ from letta.providers import ProviderUpdate
6
+ from letta.utils import enforce_types
7
+
8
+
9
+ class ProviderManager:
10
+
11
+ def __init__(self):
12
+ from letta.server.server import db_context
13
+
14
+ self.session_maker = db_context
15
+
16
+ @enforce_types
17
+ def create_provider(self, provider: PydanticProvider) -> PydanticProvider:
18
+ """Create a new provider if it doesn't already exist."""
19
+ with self.session_maker() as session:
20
+ new_provider = ProviderModel(**provider.model_dump())
21
+ new_provider.create(session)
22
+ return new_provider.to_pydantic()
23
+
24
+ @enforce_types
25
+ def update_provider(self, provider_update: ProviderUpdate) -> PydanticProvider:
26
+ """Update provider details."""
27
+ with self.session_maker() as session:
28
+ # Retrieve the existing provider by ID
29
+ existing_provider = ProviderModel.read(db_session=session, identifier=provider_update.id)
30
+
31
+ # Update only the fields that are provided in ProviderUpdate
32
+ update_data = provider_update.model_dump(exclude_unset=True, exclude_none=True)
33
+ for key, value in update_data.items():
34
+ setattr(existing_provider, key, value)
35
+
36
+ # Commit the updated provider
37
+ existing_provider.update(session)
38
+ return existing_provider.to_pydantic()
39
+
40
+ @enforce_types
41
+ def delete_provider_by_id(self, provider_id: str):
42
+ """Delete a provider."""
43
+ with self.session_maker() as session:
44
+ # Delete from provider table
45
+ provider = ProviderModel.read(db_session=session, identifier=provider_id)
46
+ provider.hard_delete(session)
47
+
48
+ session.commit()
49
+
50
+ @enforce_types
51
+ def list_providers(self, cursor: Optional[str] = None, limit: Optional[int] = 50) -> List[PydanticProvider]:
52
+ """List providers with pagination using cursor (id) and limit."""
53
+ with self.session_maker() as session:
54
+ results = ProviderModel.list(db_session=session, cursor=cursor, limit=limit)
55
+ return [provider.to_pydantic() for provider in results]
56
+
57
+ @enforce_types
58
+ def get_anthropic_key_override(self) -> Optional[str]:
59
+ """Helper function to fetch custom anthropic key for v0 BYOK feature"""
60
+ providers = self.list_providers(limit=1)
61
+ if len(providers) == 1 and providers[0].name == "anthropic":
62
+ return providers[0].api_key
63
+ return None
@@ -98,7 +98,7 @@ class ToolExecutionSandbox:
98
98
  os.environ.clear()
99
99
  os.environ.update(original_env) # Restore original environment variables
100
100
 
101
- def run_local_dir_sandbox(self, agent_state: AgentState) -> SandboxRunResult:
101
+ def run_local_dir_sandbox(self, agent_state: Optional[AgentState] = None) -> SandboxRunResult:
102
102
  sbx_config = self.sandbox_config_manager.get_or_create_default_sandbox_config(sandbox_type=SandboxType.LOCAL, actor=self.user)
103
103
  local_configs = sbx_config.get_local_config()
104
104
 
@@ -107,6 +107,10 @@ class ToolExecutionSandbox:
107
107
  env = os.environ.copy()
108
108
  env.update(env_vars)
109
109
 
110
+ # Get environment variables for this agent specifically
111
+ if agent_state:
112
+ env.update(agent_state.get_agent_env_vars_as_dict())
113
+
110
114
  # Safety checks
111
115
  if not os.path.isdir(local_configs.sandbox_dir):
112
116
  raise FileNotFoundError(f"Sandbox directory does not exist: {local_configs.sandbox_dir}")
@@ -273,7 +277,7 @@ class ToolExecutionSandbox:
273
277
 
274
278
  # e2b sandbox specific functions
275
279
 
276
- def run_e2b_sandbox(self, agent_state: AgentState) -> SandboxRunResult:
280
+ def run_e2b_sandbox(self, agent_state: Optional[AgentState] = None) -> SandboxRunResult:
277
281
  sbx_config = self.sandbox_config_manager.get_or_create_default_sandbox_config(sandbox_type=SandboxType.E2B, actor=self.user)
278
282
  sbx = self.get_running_e2b_sandbox_with_same_state(sbx_config)
279
283
  if not sbx or self.force_recreate:
@@ -292,15 +296,18 @@ class ToolExecutionSandbox:
292
296
  # Get environment variables for the sandbox
293
297
  # TODO: We set limit to 100 here, but maybe we want it uncapped? Realistically this should be fine.
294
298
  env_vars = self.sandbox_config_manager.get_sandbox_env_vars_as_dict(sandbox_config_id=sbx_config.id, actor=self.user, limit=100)
299
+ # Get environment variables for this agent specifically
300
+ if agent_state:
301
+ env_vars.update(agent_state.get_agent_env_vars_as_dict())
302
+
295
303
  code = self.generate_execution_script(agent_state=agent_state)
296
304
  execution = sbx.run_code(code, envs=env_vars)
297
305
 
298
306
  if execution.results:
299
307
  func_return, agent_state = self.parse_best_effort(execution.results[0].text)
300
308
  elif execution.error:
301
- logger.error(f"Executing tool {self.tool_name} failed with {execution.error}")
302
- logger.error(f"E2B Sandbox configurations: {sbx_config}")
303
- logger.error(f"E2B Sandbox ID: {sbx.sandbox_id}")
309
+ logger.error(f"Executing tool {self.tool_name} raised a {execution.error.name} with message: \n{execution.error.value}")
310
+ logger.error(f"Traceback from e2b sandbox: \n{execution.error.traceback}")
304
311
  func_return = get_friendly_error_msg(
305
312
  function_name=self.tool_name, exception_name=execution.error.name, exception_message=execution.error.value
306
313
  )
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: letta-nightly
3
- Version: 0.6.7.dev20250108104013
3
+ Version: 0.6.8.dev20250109011239
4
4
  Summary: Create LLM agents with long-term memory and custom tools
5
5
  License: Apache License
6
6
  Author: Letta Team
7
7
  Author-email: contact@letta.com
8
- Requires-Python: >=3.10,<4.0
8
+ Requires-Python: >=3.10,<3.14
9
9
  Classifier: License :: Other/Proprietary License
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3.10
@@ -1,6 +1,6 @@
1
- letta/__init__.py,sha256=5MP4Aw9hp_BhgM50dsKzMUw6Bmx4buIb4eZnMnkAuk8,989
1
+ letta/__init__.py,sha256=-CRF0Bm3fnfx91Zwqgy6SjNRFRTorD37JtSJnVMpRGQ,991
2
2
  letta/__main__.py,sha256=6Hs2PV7EYc5Tid4g4OtcLXhqVHiNYTGzSBdoOnW2HXA,29
3
- letta/agent.py,sha256=0mAWMJ6NwOEIupY4n21Tb7MdWY3QsYaY4uiqSb0y-cE,54768
3
+ letta/agent.py,sha256=EhExlfnS20MNTu8M8EAFriaabbrj_uDNJloEXNuxOTk,54891
4
4
  letta/benchmark/benchmark.py,sha256=ebvnwfp3yezaXOQyGXkYCDYpsmre-b9hvNtnyx4xkG0,3701
5
5
  letta/benchmark/constants.py,sha256=aXc5gdpMGJT327VuxsT5FngbCK2J41PQYeICBO7g_RE,536
6
6
  letta/chat_only_agent.py,sha256=ECqJS7KzXOsNkJc9mv7reKbcxBI_PKP_PQyk95tsT1Y,4761
@@ -8,11 +8,11 @@ letta/cli/cli.py,sha256=_uGKM-RvGLGf7y8iWjkLgLTxIw7uWrdCdL5ETUOCkUs,16472
8
8
  letta/cli/cli_config.py,sha256=I5J8D0OpsDDXCTOWFqjmxQuZCGrC1oCuNbVkrKwg4VM,8544
9
9
  letta/cli/cli_load.py,sha256=xFw-CuzjChcIptaqQ1XpDROENt0JSjyPeiQ0nmEeO1k,2706
10
10
  letta/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- letta/client/client.py,sha256=gXtht3oVJAelexW4japVriN7Htc0mppuUwEf7a-dNiI,126954
11
+ letta/client/client.py,sha256=pdCcfsimPKrY3QFbLBLV8V1PNf3pkicAIgN_mfTSCWs,127021
12
12
  letta/client/streaming.py,sha256=Hz2j_hQZG2g7uhucjx2p3ybf2qjPT-vmIGCHGo87iCQ,4677
13
13
  letta/client/utils.py,sha256=VCGV-op5ZSmurd4yw7Vhf93XDQ0BkyBT8qsuV7EqfiU,2859
14
14
  letta/config.py,sha256=JFGY4TWW0Wm5fTbZamOwWqk5G8Nn-TXyhgByGoAqy2c,12375
15
- letta/constants.py,sha256=Yelpw8qUuAXPJhaGPitkab9_e6SzaYZDokbwVEZzXE4,7086
15
+ letta/constants.py,sha256=1n_SEPtdRKMzrHRSG1JgHYDJKeFMLPY0garxkqj47_o,7135
16
16
  letta/credentials.py,sha256=D9mlcPsdDWlIIXQQD8wSPE9M_QvsRrb0p3LB5i9OF5Q,5806
17
17
  letta/data_sources/connectors.py,sha256=L-WL-znjaRstMwSunHf3xDywjvgnbjnUR9rUpL6Ypo0,7023
18
18
  letta/data_sources/connectors_helper.py,sha256=2TQjCt74fCgT5sw1AP8PalDEk06jPBbhrPG4HVr-WLs,3371
@@ -22,8 +22,8 @@ letta/functions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  letta/functions/function_sets/base.py,sha256=bOiitkhzqYKwZBiRYrx29AlordiA5IrXw25eVSRK8BY,5984
23
23
  letta/functions/function_sets/extras.py,sha256=sNY5oavQ5ZmO5GpAtnm8hkWokqwqB8ClPB2VOL-B8MM,4719
24
24
  letta/functions/functions.py,sha256=evH6GKnIJwVVre1Xre2gaSIqREv4eNM4DiWOhn8PMqg,3299
25
- letta/functions/helpers.py,sha256=fJo4gPvWpkvR7jn0HucRorz4VlpYVqmYsiX1RetnnSY,8569
26
- letta/functions/schema_generator.py,sha256=agG0HTha-Ux2vL15tsWRAXmIMqlqce8vduiQEaw6RWY,17610
25
+ letta/functions/helpers.py,sha256=PkhzSHc8gZBxX2NHFaDYX0ZwUK9kuGQbz1zpIZ-KXVo,8860
26
+ letta/functions/schema_generator.py,sha256=u8ix-spnLeP-epFMxP4jF23_aQDa-yCUIW2_O2CBOuo,17561
27
27
  letta/helpers/__init__.py,sha256=p0luQ1Oe3Skc6sH4O58aHHA3Qbkyjifpuq0DZ1GAY0U,59
28
28
  letta/helpers/tool_rule_solver.py,sha256=VnJfqb5L1Lcipc_tBVGj0om60GKQkMkNLgg6X9VZl2c,6210
29
29
  letta/humans/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -37,7 +37,7 @@ letta/llm_api/azure_openai_constants.py,sha256=oXtKrgBFHf744gyt5l1thILXgyi8NDNUr
37
37
  letta/llm_api/cohere.py,sha256=H5kzYH_aQAnGNq7lip7XyKGLEOKC318Iw0_tiTP6kc4,14772
38
38
  letta/llm_api/google_ai.py,sha256=0rkWKGzOGUvMXycbflqJMUQ3zFZ1VFLxWf0h7uGtPYQ,17543
39
39
  letta/llm_api/helpers.py,sha256=iP9EswPflaRzsmLqQuMGt1OCUQgPrPq1xTjrqmMKPiA,13675
40
- letta/llm_api/llm_api_tools.py,sha256=T8FL2snn6STckMjo7oPNS-xdkc5466G6Jntbl7LXNfQ,18175
40
+ letta/llm_api/llm_api_tools.py,sha256=DnWsyowH_re5Zvd8-XNfGvB7KkjqcfdkqjmlVvM7_BU,18444
41
41
  letta/llm_api/mistral.py,sha256=fHdfD9ug-rQIk2qn8tRKay1U6w9maF11ryhKi91FfXM,1593
42
42
  letta/llm_api/openai.py,sha256=cLJOXN5E0k7E2mtYQCiEmLtIDdrNwq4tebRfcodFN6c,24091
43
43
  letta/local_llm/README.md,sha256=hFJyw5B0TU2jrh9nb0zGZMgdH-Ei1dSRfhvPQG_NSoU,168
@@ -85,7 +85,7 @@ letta/offline_memory_agent.py,sha256=Wc2_je3oXxXcaiPPNPxc78A3IXVsiK6Q7X3t_SrlHck
85
85
  letta/openai_backcompat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
86
  letta/openai_backcompat/openai_object.py,sha256=Y1ZS1sATP60qxJiOsjOP3NbwSzuzvkNAvb3DeuhM5Uk,13490
87
87
  letta/orm/__all__.py,sha256=2gh2MZTkA3Hw67VWVKK3JIStJOqTeLdpCvYSVYNeEDA,692
88
- letta/orm/__init__.py,sha256=EEfDxoB9qjIRetKyOjnMxiAbsADr5xvCKdHPSiR1JEE,698
88
+ letta/orm/__init__.py,sha256=cVnGGFjrAIuRpguw10l5moUG3Z5vKHqQjVsCv6uww3M,764
89
89
  letta/orm/agent.py,sha256=Uvez0vJGyuL20gVTSIvqYpVp1C2udLJlfQrGvLZCeH8,6162
90
90
  letta/orm/agents_tags.py,sha256=dYSnHz4IWBjyOiQ4RJomX3P0QN76JTlEZEw5eJM6Emg,925
91
91
  letta/orm/base.py,sha256=47Pyo6iGPlJoT8oeXZWl3E7XHbPzcB81EueoFzeXbxE,2691
@@ -98,8 +98,9 @@ letta/orm/file.py,sha256=7_p7LxityP3NQZVURQYG0kgcZhEkVuMN0Fj4h9YOe1w,1780
98
98
  letta/orm/job.py,sha256=If-qSTJW4t5h-6Jolw3tS3-xMZEaPIbXe3S0GMf_FXI,1102
99
99
  letta/orm/message.py,sha256=Ui3mMZTAObP7RvmNnqCFudw8Pkt8IAPTlIjCSCsVDFA,1560
100
100
  letta/orm/mixins.py,sha256=9c79Kfr-Z1hL-SDYKeoptx_yMTbBwJJBo9nrKEzSDAc,1622
101
- letta/orm/organization.py,sha256=I29kQf2xpo1GFKrjAoifCePKPLuS9DVpLEdQ8eSjKd8,2725
101
+ letta/orm/organization.py,sha256=b12iASuskPnG2yHyFh8p2BFROkoqMPEYUFMuVcFPCHs,2897
102
102
  letta/orm/passage.py,sha256=tm5YhUozLR9hN7odGCqCniTl-3GDiFNz3LWAxullaGA,3132
103
+ letta/orm/provider.py,sha256=Efy4dATyl1AbT_mGpKce5H7sKNqCHVQhkcSZpXgTw-k,797
103
104
  letta/orm/sandbox_config.py,sha256=DyOy_1_zCMlp13elCqPcuuA6OwUove6mrjhcpROTg50,4150
104
105
  letta/orm/source.py,sha256=xM3Iwy3xzYdoZja9BZrQwyAnPf5iksaQOs8HlNCvb_c,2031
105
106
  letta/orm/sources_agents.py,sha256=Ik_PokCBrXRd9wXWomeNeb8EtLUwjb9VMZ8LWXqpK5A,473
@@ -134,9 +135,9 @@ letta/prompts/system/memgpt_modified_chat.txt,sha256=F_yD4ZcR4aGDE3Z98tI7e609GYe
134
135
  letta/prompts/system/memgpt_modified_o1.txt,sha256=objnDgnxpF3-MmU28ZqZ7-TOG8UlHBM_HMyAdSDWK88,5492
135
136
  letta/prompts/system/memgpt_offline_memory.txt,sha256=rWEJeF-6aiinjkJM9hgLUYCmlEcC_HekYB1bjEUYq6M,2460
136
137
  letta/prompts/system/memgpt_offline_memory_chat.txt,sha256=ituh7gDuio7nC2UKFB7GpBq6crxb8bYedQfJ0ADoPgg,3949
137
- letta/providers.py,sha256=81BvvtS0jaerv86KRPWrSul76LVKdYvkzT2bGbheeI0,26561
138
+ letta/providers.py,sha256=f-ZbMBmvX1rtVWuW-GS4mihFjWHg343keAzqVb9NgWY,27468
138
139
  letta/pytest.ini,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
139
- letta/schemas/agent.py,sha256=5Eggk-Q11zj3tZoxZ8cs0fYYXTtEAyVxNOEy1o1Luk0,11032
140
+ letta/schemas/agent.py,sha256=0qXYf31IxPzE3rq-cYqv4vIQCB9WMRZYAbsqE6JBvVY,11508
140
141
  letta/schemas/block.py,sha256=pVDH8jr5r-oxdX4cK9dX2wXyLBzgGKQOBWOzqZSeBog,5944
141
142
  letta/schemas/embedding_config.py,sha256=8K2EGVQ26F3zjY1Wj3v_hsrA-1qICshVMGRlKPSATfg,3354
142
143
  letta/schemas/enums.py,sha256=f8SVJqb0dzhlNCBN2SgeM4ZMHX5LMyhln1SCJAgXeow,1068
@@ -146,7 +147,7 @@ letta/schemas/health.py,sha256=zT6mYovvD17iJRuu2rcaQQzbEEYrkwvAE9TB7iU824c,139
146
147
  letta/schemas/job.py,sha256=vRVVpMCHTxot9uaalLS8RARnqzJWvcLB1XP5XRBioPc,1398
147
148
  letta/schemas/letta_base.py,sha256=v3OvpVFVUfcuK1lIyTjM0x4fmWeWQw1DdlhKXHBUCz8,3608
148
149
  letta/schemas/letta_message.py,sha256=SpAxAEFQa-JMzxIQ5cqz0TENB5S9WsdrTAHGUJBLCQQ,8040
149
- letta/schemas/letta_request.py,sha256=Hfb66FB1tXmrpEX4_yLQVfTrTSMbPYeEvZY-vqW9Tj8,981
150
+ letta/schemas/letta_request.py,sha256=nyLneFcP1a6xAWknOfKDFt1WNQykuEFH4e9F15QIxVY,1190
150
151
  letta/schemas/letta_response.py,sha256=1Z7nDm5fPSWeiGVTtA-JkoLOaFbeyE4FZPK2kGlQ_Uw,7610
151
152
  letta/schemas/llm_config.py,sha256=zxygt_4imoEAgxMLO1nxNVAL-2ePGsOKEt-vQJOc0ow,4585
152
153
  letta/schemas/memory.py,sha256=dWF1AWhQKEp1MJ6yz8wVYrWNsmA2ADREAz2lS3d8I6c,10229
@@ -181,24 +182,25 @@ letta/server/rest_api/routers/openai/assistants/schemas.py,sha256=ZWUrmkvDMeywlx
181
182
  letta/server/rest_api/routers/openai/chat_completions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
182
183
  letta/server/rest_api/routers/openai/chat_completions/chat_completions.py,sha256=szOelaigEMNNzlvl5ZkS4KDzdyLhv2ATZ8XuaDPN3Jc,4820
183
184
  letta/server/rest_api/routers/v1/__init__.py,sha256=6Aw18C9of0ayRNyFYUK_-nxajeVLaYau1bLw-tg_OQ4,753
184
- letta/server/rest_api/routers/v1/agents.py,sha256=GT3szDFEmNrhQ4mZpPa9IQpEcfh4tNpqwRyUg2YDw8k,30682
185
+ letta/server/rest_api/routers/v1/agents.py,sha256=S79Bz0y-MGPQfzXuPPDNjJvBDBRQOKE_ixAqENx9J8Q,30986
185
186
  letta/server/rest_api/routers/v1/blocks.py,sha256=IJ2pppwNooaUjIwyBALnKL4sJ8idW8cVJlY-VH_J9HY,4803
186
187
  letta/server/rest_api/routers/v1/health.py,sha256=pKCuVESlVOhGIb4VC4K-H82eZqfghmT6kvj2iOkkKuc,401
187
188
  letta/server/rest_api/routers/v1/jobs.py,sha256=-tEyuIxlXZfPREeMks-sRzHwhKE2xxgzbXeEbBAS2Q8,2730
188
189
  letta/server/rest_api/routers/v1/llms.py,sha256=TcyvSx6MEM3je5F4DysL7ligmssL_pFlJaaO4uL95VY,877
189
190
  letta/server/rest_api/routers/v1/organizations.py,sha256=tyqVzXTpMtk3sKxI3Iz4aS6RhbGEbXDzFBB_CpW18v4,2080
191
+ letta/server/rest_api/routers/v1/providers.py,sha256=7_921hS6AsvOG-9LeGsF61fM_8cP7Ez-AVUBX-G1iVs,2358
190
192
  letta/server/rest_api/routers/v1/sandbox_configs.py,sha256=3XjI2QPLp_Ev3AuVx1mHP4FbTHyPjQ6apZ--5ajhmxI,5131
191
193
  letta/server/rest_api/routers/v1/sources.py,sha256=EJ-VCqiKtaiYuivZrWx1gYSNUKnWJuduSm-L_2ljhLc,9913
192
194
  letta/server/rest_api/routers/v1/tools.py,sha256=WpkM1UotqWyr61zBpEU3tAaoUfXIDMxJbjfPqpg1jpI,12720
193
195
  letta/server/rest_api/routers/v1/users.py,sha256=EBQe9IfCG3kzHpKmotz4yVGZioXz3SCSRy5yEhJK8hU,2293
194
196
  letta/server/rest_api/static_files.py,sha256=NG8sN4Z5EJ8JVQdj19tkFa9iQ1kBPTab9f_CUxd_u4Q,3143
195
197
  letta/server/rest_api/utils.py,sha256=M4VE76TtC9qorvszq1x7MTBW9jSWgtUUCRahqpJNYNc,3953
196
- letta/server/server.py,sha256=hD-GY1OK71khIstqACJf8HFM-SKGPTo9fUVr_dbOilM,49969
198
+ letta/server/server.py,sha256=on67yQmKavUM2HbHCl127QNfhTZhUO7L8SxNOYbjJd4,50507
197
199
  letta/server/startup.sh,sha256=722uKJWB2C4q3vjn39De2zzPacaZNw_1fN1SpLGjKIo,1569
198
200
  letta/server/static_files/assets/index-048c9598.js,sha256=mR16XppvselwKCcNgONs4L7kZEVa4OEERm4lNZYtLSk,146819
199
- letta/server/static_files/assets/index-0e31b727.css,sha256=DjG3J3RSFLcinzoisOYYLiyTAIe5Uaxge3HE-DmQIsU,7688
201
+ letta/server/static_files/assets/index-0e31b727.css,sha256=SBbja96uiQVLDhDOroHgM6NSl7tS4lpJRCREgSS_hA8,7672
200
202
  letta/server/static_files/favicon.ico,sha256=DezhLdFSbM8o81wCOZcV3riq7tFUOGQD4h6-vr-HuU0,342
201
- letta/server/static_files/index.html,sha256=-9bodsoqpeSavIpNlaM3Z36_xjaotjXPCLLq9J8xFWg,1198
203
+ letta/server/static_files/index.html,sha256=sY5ZwjwJJysQWDJZGi5VQSJUkZH9gwQRGn0Hto2Vcfo,1194
202
204
  letta/server/static_files/memgpt_logo_transparent.png,sha256=7l6niNb4MlUILxLlUZPxIE1TEHj_Z9f9XDxoST3d7Vw,85383
203
205
  letta/server/utils.py,sha256=rRvW6L1lzau4u9boamiyZH54lf5tQ91ypXzUW9cfSPA,1667
204
206
  letta/server/ws_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -207,7 +209,7 @@ letta/server/ws_api/interface.py,sha256=TWl9vkcMCnLsUtgsuENZ-ku2oMDA-OUTzLh_yNRo
207
209
  letta/server/ws_api/protocol.py,sha256=M_-gM5iuDBwa1cuN2IGNCG5GxMJwU2d3XW93XALv9s8,1821
208
210
  letta/server/ws_api/server.py,sha256=cBSzf-V4zT1bL_0i54OTI3cMXhTIIxqjSRF8pYjk7fg,5835
209
211
  letta/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
210
- letta/services/agent_manager.py,sha256=F8vweprrii3y-QwlN3sFneS5ylxhQUQbJpqAiIb5_4g,41104
212
+ letta/services/agent_manager.py,sha256=r5HTYtCiSNE-hkloVGY0T2PflAvtmirQRBxVuPw03Zs,41912
211
213
  letta/services/block_manager.py,sha256=HUj9HKW2LvAsENEsgCO3Pf3orvSy6XOimev38VKmRZ8,4929
212
214
  letta/services/helpers/agent_manager_helper.py,sha256=Q_nRk-eovoYTzLxOYvUbnsQVLWdRvFvjk8OcLUfjkJU,10568
213
215
  letta/services/job_manager.py,sha256=FrkSXloke48CZKuzlYdysxM5gKWoTu7FRigPrs_YW4A,3645
@@ -215,9 +217,10 @@ letta/services/message_manager.py,sha256=a7U0MfgaNAdjbls7ZtUdS7eJ6prJaMkE0NIHgtz
215
217
  letta/services/organization_manager.py,sha256=hJI86_FErkRaW-VLBBmvmmciIXN59LN0mEMm78C36kQ,3331
216
218
  letta/services/passage_manager.py,sha256=Lq1caspE1VGmT7vlsUOuJVRflJZ122qfG0dmNGm_6o8,7691
217
219
  letta/services/per_agent_lock_manager.py,sha256=porM0cKKANQ1FvcGXOO_qM7ARk5Fgi1HVEAhXsAg9-4,546
220
+ letta/services/provider_manager.py,sha256=wCYgl2toWsuOHwFGkz0i94G0hyWtFNyRLUzB2ElTckw,2589
218
221
  letta/services/sandbox_config_manager.py,sha256=HrlFv-KV9fRSERIEAVuiMynEvA_AQWQVGmBubCkfQC4,13217
219
222
  letta/services/source_manager.py,sha256=ZtLQikeJjwAq49f0d4WxUzyUN3LZBqWCZI4a-AzEMWQ,7643
220
- letta/services/tool_execution_sandbox.py,sha256=L8wCJvv6tooNlfVhdIyIfJn06iI3Y1lW0nIqCydGG_M,22024
223
+ letta/services/tool_execution_sandbox.py,sha256=xj0LYCmyyJs31_7lZn7lHypC6H7veppYmaXF10IwvnY,22368
221
224
  letta/services/tool_manager.py,sha256=eKhvGYNBq8MOwfuk-GyqiTdEcxRn4srYvTJqj-HgTKA,7686
222
225
  letta/services/tool_sandbox_env/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
223
226
  letta/services/user_manager.py,sha256=oqLF9C4mGbN0TaGj7wMpb2RH2bUg6OJJcdyaWv370rQ,4272
@@ -226,8 +229,8 @@ letta/streaming_interface.py,sha256=lo2VAQRUJOdWTijwnXuKOC9uejqr2siUAEmZiQUXkj8,
226
229
  letta/streaming_utils.py,sha256=329fsvj1ZN0r0LpQtmMPZ2vSxkDBIUUwvGHZFkjm2I8,11745
227
230
  letta/system.py,sha256=buKYPqG5n2x41hVmWpu6JUpyd7vTWED9Km2_M7dLrvk,6960
228
231
  letta/utils.py,sha256=1-HhTZEw7j5fXI2ukdto0y1cZ-I8wpHKf7rqtdwFnT4,33382
229
- letta_nightly-0.6.7.dev20250108104013.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
230
- letta_nightly-0.6.7.dev20250108104013.dist-info/METADATA,sha256=PIPpcOf12W2qFNgyKEFe9437RVnXxo9wXR4nQcZtDd8,21693
231
- letta_nightly-0.6.7.dev20250108104013.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
232
- letta_nightly-0.6.7.dev20250108104013.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
233
- letta_nightly-0.6.7.dev20250108104013.dist-info/RECORD,,
232
+ letta_nightly-0.6.8.dev20250109011239.dist-info/LICENSE,sha256=mExtuZ_GYJgDEI38GWdiEYZizZS4KkVt2SF1g_GPNhI,10759
233
+ letta_nightly-0.6.8.dev20250109011239.dist-info/METADATA,sha256=M3wA8Pns3Zr3NmruQ3u7bplplbBt2mHjt2oV54k9pdE,21694
234
+ letta_nightly-0.6.8.dev20250109011239.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
235
+ letta_nightly-0.6.8.dev20250109011239.dist-info/entry_points.txt,sha256=2zdiyGNEZGV5oYBuS-y2nAAgjDgcC9yM_mHJBFSRt5U,40
236
+ letta_nightly-0.6.8.dev20250109011239.dist-info/RECORD,,