letta-nightly 0.6.1.dev20241206104246__py3-none-any.whl → 0.6.1.dev20241208104134__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.

Files changed (49) hide show
  1. letta/agent.py +68 -76
  2. letta/agent_store/db.py +1 -77
  3. letta/agent_store/storage.py +0 -5
  4. letta/cli/cli.py +1 -4
  5. letta/client/client.py +11 -14
  6. letta/constants.py +1 -0
  7. letta/functions/function_sets/base.py +33 -5
  8. letta/functions/helpers.py +3 -3
  9. letta/llm_api/openai.py +0 -1
  10. letta/local_llm/llm_chat_completion_wrappers/chatml.py +13 -1
  11. letta/main.py +2 -2
  12. letta/memory.py +4 -82
  13. letta/metadata.py +0 -35
  14. letta/o1_agent.py +7 -2
  15. letta/offline_memory_agent.py +6 -0
  16. letta/orm/__init__.py +2 -0
  17. letta/orm/file.py +1 -1
  18. letta/orm/message.py +64 -0
  19. letta/orm/mixins.py +16 -0
  20. letta/orm/organization.py +1 -0
  21. letta/orm/sqlalchemy_base.py +118 -26
  22. letta/schemas/letta_base.py +7 -6
  23. letta/schemas/message.py +6 -12
  24. letta/schemas/tool.py +18 -11
  25. letta/server/rest_api/app.py +2 -3
  26. letta/server/rest_api/routers/v1/agents.py +7 -6
  27. letta/server/rest_api/routers/v1/blocks.py +2 -2
  28. letta/server/rest_api/routers/v1/tools.py +26 -4
  29. letta/server/rest_api/utils.py +3 -1
  30. letta/server/server.py +67 -62
  31. letta/server/static_files/assets/index-43ab4d62.css +1 -0
  32. letta/server/static_files/assets/index-4848e3d7.js +40 -0
  33. letta/server/static_files/index.html +2 -2
  34. letta/services/block_manager.py +1 -1
  35. letta/services/message_manager.py +194 -0
  36. letta/services/organization_manager.py +6 -9
  37. letta/services/sandbox_config_manager.py +16 -1
  38. letta/services/source_manager.py +1 -1
  39. letta/services/tool_manager.py +2 -4
  40. letta/services/user_manager.py +1 -1
  41. {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241208104134.dist-info}/METADATA +2 -2
  42. {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241208104134.dist-info}/RECORD +45 -45
  43. letta/agent_store/lancedb.py +0 -177
  44. letta/persistence_manager.py +0 -149
  45. letta/server/static_files/assets/index-1b5d1a41.js +0 -271
  46. letta/server/static_files/assets/index-56a3f8c6.css +0 -1
  47. {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241208104134.dist-info}/LICENSE +0 -0
  48. {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241208104134.dist-info}/WHEEL +0 -0
  49. {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241208104134.dist-info}/entry_points.txt +0 -0
@@ -1,177 +0,0 @@
1
- # type: ignore
2
-
3
- import uuid
4
- from datetime import datetime
5
- from typing import Dict, Iterator, List, Optional
6
-
7
- from lancedb.pydantic import LanceModel, Vector
8
-
9
- from letta.agent_store.storage import StorageConnector, TableType
10
- from letta.config import AgentConfig, LettaConfig
11
- from letta.schemas.message import Message, Passage, Record
12
-
13
- """ Initial implementation - not complete """
14
-
15
-
16
- def get_db_model(table_name: str, table_type: TableType):
17
- config = LettaConfig.load()
18
-
19
- if table_type == TableType.ARCHIVAL_MEMORY or table_type == TableType.PASSAGES:
20
- # create schema for archival memory
21
- class PassageModel(LanceModel):
22
- """Defines data model for storing Passages (consisting of text, embedding)"""
23
-
24
- id: uuid.UUID
25
- user_id: str
26
- text: str
27
- file_id: str
28
- agent_id: str
29
- data_source: str
30
- embedding: Vector(config.default_embedding_config.embedding_dim)
31
- metadata_: Dict
32
-
33
- def __repr__(self):
34
- return f"<Passage(passage_id='{self.id}', text='{self.text}', embedding='{self.embedding})>"
35
-
36
- def to_record(self):
37
- return Passage(
38
- text=self.text,
39
- embedding=self.embedding,
40
- file_id=self.file_id,
41
- user_id=self.user_id,
42
- id=self.id,
43
- data_source=self.data_source,
44
- agent_id=self.agent_id,
45
- metadata=self.metadata_,
46
- )
47
-
48
- return PassageModel
49
- elif table_type == TableType.RECALL_MEMORY:
50
-
51
- class MessageModel(LanceModel):
52
- """Defines data model for storing Message objects"""
53
-
54
- __abstract__ = True # this line is necessary
55
-
56
- # Assuming message_id is the primary key
57
- id: uuid.UUID
58
- user_id: str
59
- agent_id: str
60
-
61
- # openai info
62
- role: str
63
- name: str
64
- text: str
65
- model: str
66
- user: str
67
-
68
- # function info
69
- function_name: str
70
- function_args: str
71
- function_response: str
72
-
73
- embedding = Vector(config.default_embedding_config.embedding_dim)
74
-
75
- # Add a datetime column, with default value as the current time
76
- created_at = datetime
77
-
78
- def __repr__(self):
79
- return f"<Message(message_id='{self.id}', text='{self.text}', embedding='{self.embedding})>"
80
-
81
- def to_record(self):
82
- return Message(
83
- user_id=self.user_id,
84
- agent_id=self.agent_id,
85
- role=self.role,
86
- name=self.name,
87
- text=self.text,
88
- model=self.model,
89
- function_name=self.function_name,
90
- function_args=self.function_args,
91
- function_response=self.function_response,
92
- embedding=self.embedding,
93
- created_at=self.created_at,
94
- id=self.id,
95
- )
96
-
97
- """Create database model for table_name"""
98
- return MessageModel
99
-
100
- else:
101
- raise ValueError(f"Table type {table_type} not implemented")
102
-
103
-
104
- class LanceDBConnector(StorageConnector):
105
- """Storage via LanceDB"""
106
-
107
- # TODO: this should probably eventually be moved into a parent DB class
108
-
109
- def __init__(self, name: Optional[str] = None, agent_config: Optional[AgentConfig] = None):
110
- # TODO
111
- pass
112
-
113
- def generate_where_filter(self, filters: Dict) -> str:
114
- where_filters = []
115
- for key, value in filters.items():
116
- where_filters.append(f"{key}={value}")
117
- return where_filters.join(" AND ")
118
-
119
- @abstractmethod
120
- def get_all_paginated(self, filters: Optional[Dict] = {}, page_size: Optional[int] = 1000) -> Iterator[List[Record]]:
121
- # TODO
122
- pass
123
-
124
- @abstractmethod
125
- def get_all(self, filters: Optional[Dict] = {}, limit=10) -> List[Record]:
126
- # TODO
127
- pass
128
-
129
- @abstractmethod
130
- def get(self, id: uuid.UUID) -> Optional[Record]:
131
- # TODO
132
- pass
133
-
134
- @abstractmethod
135
- def size(self, filters: Optional[Dict] = {}) -> int:
136
- # TODO
137
- pass
138
-
139
- @abstractmethod
140
- def insert(self, record: Record):
141
- # TODO
142
- pass
143
-
144
- @abstractmethod
145
- def insert_many(self, records: List[Record], show_progress=False):
146
- # TODO
147
- pass
148
-
149
- @abstractmethod
150
- def query(self, query: str, query_vec: List[float], top_k: int = 10, filters: Optional[Dict] = {}) -> List[Record]:
151
- # TODO
152
- pass
153
-
154
- @abstractmethod
155
- def query_date(self, start_date, end_date):
156
- # TODO
157
- pass
158
-
159
- @abstractmethod
160
- def query_text(self, query):
161
- # TODO
162
- pass
163
-
164
- @abstractmethod
165
- def delete_table(self):
166
- # TODO
167
- pass
168
-
169
- @abstractmethod
170
- def delete(self, filters: Optional[Dict] = {}):
171
- # TODO
172
- pass
173
-
174
- @abstractmethod
175
- def save(self):
176
- # TODO
177
- pass
@@ -1,149 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from datetime import datetime
3
- from typing import List
4
-
5
- from letta.memory import BaseRecallMemory, EmbeddingArchivalMemory
6
- from letta.schemas.agent import AgentState
7
- from letta.schemas.memory import Memory
8
- from letta.schemas.message import Message
9
- from letta.utils import printd
10
-
11
-
12
- def parse_formatted_time(formatted_time: str):
13
- # parse times returned by letta.utils.get_formatted_time()
14
- try:
15
- return datetime.strptime(formatted_time.strip(), "%Y-%m-%d %I:%M:%S %p %Z%z")
16
- except:
17
- return datetime.strptime(formatted_time.strip(), "%Y-%m-%d %I:%M:%S %p")
18
-
19
-
20
- class PersistenceManager(ABC):
21
- @abstractmethod
22
- def trim_messages(self, num):
23
- pass
24
-
25
- @abstractmethod
26
- def prepend_to_messages(self, added_messages):
27
- pass
28
-
29
- @abstractmethod
30
- def append_to_messages(self, added_messages):
31
- pass
32
-
33
- @abstractmethod
34
- def swap_system_message(self, new_system_message):
35
- pass
36
-
37
- @abstractmethod
38
- def update_memory(self, new_memory):
39
- pass
40
-
41
-
42
- class LocalStateManager(PersistenceManager):
43
- """In-memory state manager has nothing to manage, all agents are held in-memory"""
44
-
45
- recall_memory_cls = BaseRecallMemory
46
- archival_memory_cls = EmbeddingArchivalMemory
47
-
48
- def __init__(self, agent_state: AgentState):
49
- # Memory held in-state useful for debugging stateful versions
50
- self.memory = agent_state.memory
51
- # self.messages = [] # current in-context messages
52
- # self.all_messages = [] # all messages seen in current session (needed if lazily synchronizing state with DB)
53
- self.archival_memory = EmbeddingArchivalMemory(agent_state)
54
- self.recall_memory = BaseRecallMemory(agent_state)
55
- # self.agent_state = agent_state
56
-
57
- def save(self):
58
- """Ensure storage connectors save data"""
59
- self.archival_memory.save()
60
- self.recall_memory.save()
61
-
62
- '''
63
- def json_to_message(self, message_json) -> Message:
64
- """Convert agent message JSON into Message object"""
65
-
66
- # get message
67
- if "message" in message_json:
68
- message = message_json["message"]
69
- else:
70
- message = message_json
71
-
72
- # get timestamp
73
- if "timestamp" in message_json:
74
- timestamp = parse_formatted_time(message_json["timestamp"])
75
- else:
76
- timestamp = get_local_time()
77
-
78
- # TODO: change this when we fully migrate to tool calls API
79
- if "function_call" in message:
80
- tool_calls = [
81
- ToolCall(
82
- id=message["tool_call_id"],
83
- tool_call_type="function",
84
- function={
85
- "name": message["function_call"]["name"],
86
- "arguments": message["function_call"]["arguments"],
87
- },
88
- )
89
- ]
90
- printd(f"Saving tool calls {[vars(tc) for tc in tool_calls]}")
91
- else:
92
- tool_calls = None
93
-
94
- # if message["role"] == "function":
95
- # message["role"] = "tool"
96
-
97
- return Message(
98
- user_id=self.agent_state.user_id,
99
- agent_id=self.agent_state.id,
100
- role=message["role"],
101
- text=message["content"],
102
- name=message["name"] if "name" in message else None,
103
- model=self.agent_state.llm_config.model,
104
- created_at=timestamp,
105
- tool_calls=tool_calls,
106
- tool_call_id=message["tool_call_id"] if "tool_call_id" in message else None,
107
- id=message["id"] if "id" in message else None,
108
- )
109
- '''
110
-
111
- def trim_messages(self, num):
112
- # printd(f"InMemoryStateManager.trim_messages")
113
- # self.messages = [self.messages[0]] + self.messages[num:]
114
- pass
115
-
116
- def prepend_to_messages(self, added_messages: List[Message]):
117
- # first tag with timestamps
118
- # added_messages = [{"timestamp": get_local_time(), "message": msg} for msg in added_messages]
119
-
120
- printd(f"{self.__class__.__name__}.prepend_to_message")
121
- # self.messages = [self.messages[0]] + added_messages + self.messages[1:]
122
-
123
- # add to recall memory
124
- self.recall_memory.insert_many([m for m in added_messages])
125
-
126
- def append_to_messages(self, added_messages: List[Message]):
127
- # first tag with timestamps
128
- # added_messages = [{"timestamp": get_local_time(), "message": msg} for msg in added_messages]
129
-
130
- printd(f"{self.__class__.__name__}.append_to_messages")
131
- # self.messages = self.messages + added_messages
132
-
133
- # add to recall memory
134
- self.recall_memory.insert_many([m for m in added_messages])
135
-
136
- def swap_system_message(self, new_system_message: Message):
137
- # first tag with timestamps
138
- # new_system_message = {"timestamp": get_local_time(), "message": new_system_message}
139
-
140
- printd(f"{self.__class__.__name__}.swap_system_message")
141
- # self.messages[0] = new_system_message
142
-
143
- # add to recall memory
144
- self.recall_memory.insert(new_system_message)
145
-
146
- def update_memory(self, new_memory: Memory):
147
- printd(f"{self.__class__.__name__}.update_memory")
148
- assert isinstance(new_memory, Memory), type(new_memory)
149
- self.memory = new_memory