letta-nightly 0.1.7.dev20240924104148__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 +24 -0
- letta/__main__.py +3 -0
- letta/agent.py +1427 -0
- letta/agent_store/chroma.py +295 -0
- letta/agent_store/db.py +546 -0
- letta/agent_store/lancedb.py +177 -0
- letta/agent_store/milvus.py +198 -0
- letta/agent_store/qdrant.py +201 -0
- letta/agent_store/storage.py +188 -0
- letta/benchmark/benchmark.py +96 -0
- letta/benchmark/constants.py +14 -0
- letta/cli/cli.py +689 -0
- letta/cli/cli_config.py +1282 -0
- letta/cli/cli_load.py +166 -0
- letta/client/__init__.py +0 -0
- letta/client/admin.py +171 -0
- letta/client/client.py +2360 -0
- letta/client/streaming.py +90 -0
- letta/client/utils.py +61 -0
- letta/config.py +484 -0
- letta/configs/anthropic.json +13 -0
- letta/configs/letta_hosted.json +11 -0
- letta/configs/openai.json +12 -0
- letta/constants.py +134 -0
- letta/credentials.py +140 -0
- letta/data_sources/connectors.py +247 -0
- letta/embeddings.py +218 -0
- letta/errors.py +26 -0
- letta/functions/__init__.py +0 -0
- letta/functions/function_sets/base.py +174 -0
- letta/functions/function_sets/extras.py +132 -0
- letta/functions/functions.py +105 -0
- letta/functions/schema_generator.py +205 -0
- letta/humans/__init__.py +0 -0
- letta/humans/examples/basic.txt +1 -0
- letta/humans/examples/cs_phd.txt +9 -0
- letta/interface.py +314 -0
- letta/llm_api/__init__.py +0 -0
- letta/llm_api/anthropic.py +383 -0
- letta/llm_api/azure_openai.py +155 -0
- letta/llm_api/cohere.py +396 -0
- letta/llm_api/google_ai.py +468 -0
- letta/llm_api/llm_api_tools.py +485 -0
- letta/llm_api/openai.py +470 -0
- letta/local_llm/README.md +3 -0
- letta/local_llm/__init__.py +0 -0
- letta/local_llm/chat_completion_proxy.py +279 -0
- letta/local_llm/constants.py +31 -0
- letta/local_llm/function_parser.py +68 -0
- letta/local_llm/grammars/__init__.py +0 -0
- letta/local_llm/grammars/gbnf_grammar_generator.py +1324 -0
- letta/local_llm/grammars/json.gbnf +26 -0
- letta/local_llm/grammars/json_func_calls_with_inner_thoughts.gbnf +32 -0
- letta/local_llm/groq/api.py +97 -0
- letta/local_llm/json_parser.py +202 -0
- letta/local_llm/koboldcpp/api.py +62 -0
- letta/local_llm/koboldcpp/settings.py +23 -0
- letta/local_llm/llamacpp/api.py +58 -0
- letta/local_llm/llamacpp/settings.py +22 -0
- letta/local_llm/llm_chat_completion_wrappers/__init__.py +0 -0
- letta/local_llm/llm_chat_completion_wrappers/airoboros.py +452 -0
- letta/local_llm/llm_chat_completion_wrappers/chatml.py +470 -0
- letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +387 -0
- letta/local_llm/llm_chat_completion_wrappers/dolphin.py +246 -0
- letta/local_llm/llm_chat_completion_wrappers/llama3.py +345 -0
- letta/local_llm/llm_chat_completion_wrappers/simple_summary_wrapper.py +156 -0
- letta/local_llm/llm_chat_completion_wrappers/wrapper_base.py +11 -0
- letta/local_llm/llm_chat_completion_wrappers/zephyr.py +345 -0
- letta/local_llm/lmstudio/api.py +100 -0
- letta/local_llm/lmstudio/settings.py +29 -0
- letta/local_llm/ollama/api.py +88 -0
- letta/local_llm/ollama/settings.py +32 -0
- letta/local_llm/settings/__init__.py +0 -0
- letta/local_llm/settings/deterministic_mirostat.py +45 -0
- letta/local_llm/settings/settings.py +72 -0
- letta/local_llm/settings/simple.py +28 -0
- letta/local_llm/utils.py +265 -0
- letta/local_llm/vllm/api.py +63 -0
- letta/local_llm/webui/api.py +60 -0
- letta/local_llm/webui/legacy_api.py +58 -0
- letta/local_llm/webui/legacy_settings.py +23 -0
- letta/local_llm/webui/settings.py +24 -0
- letta/log.py +76 -0
- letta/main.py +437 -0
- letta/memory.py +440 -0
- letta/metadata.py +884 -0
- letta/openai_backcompat/__init__.py +0 -0
- letta/openai_backcompat/openai_object.py +437 -0
- letta/persistence_manager.py +148 -0
- letta/personas/__init__.py +0 -0
- letta/personas/examples/anna_pa.txt +13 -0
- letta/personas/examples/google_search_persona.txt +15 -0
- letta/personas/examples/memgpt_doc.txt +6 -0
- letta/personas/examples/memgpt_starter.txt +4 -0
- letta/personas/examples/sam.txt +14 -0
- letta/personas/examples/sam_pov.txt +14 -0
- letta/personas/examples/sam_simple_pov_gpt35.txt +13 -0
- letta/personas/examples/sqldb/test.db +0 -0
- letta/prompts/__init__.py +0 -0
- letta/prompts/gpt_summarize.py +14 -0
- letta/prompts/gpt_system.py +26 -0
- letta/prompts/system/memgpt_base.txt +49 -0
- letta/prompts/system/memgpt_chat.txt +58 -0
- letta/prompts/system/memgpt_chat_compressed.txt +13 -0
- letta/prompts/system/memgpt_chat_fstring.txt +51 -0
- letta/prompts/system/memgpt_doc.txt +50 -0
- letta/prompts/system/memgpt_gpt35_extralong.txt +53 -0
- letta/prompts/system/memgpt_intuitive_knowledge.txt +31 -0
- letta/prompts/system/memgpt_modified_chat.txt +23 -0
- letta/pytest.ini +0 -0
- letta/schemas/agent.py +117 -0
- letta/schemas/api_key.py +21 -0
- letta/schemas/block.py +135 -0
- letta/schemas/document.py +21 -0
- letta/schemas/embedding_config.py +54 -0
- letta/schemas/enums.py +35 -0
- letta/schemas/job.py +38 -0
- letta/schemas/letta_base.py +80 -0
- letta/schemas/letta_message.py +175 -0
- letta/schemas/letta_request.py +23 -0
- letta/schemas/letta_response.py +28 -0
- letta/schemas/llm_config.py +54 -0
- letta/schemas/memory.py +224 -0
- letta/schemas/message.py +727 -0
- letta/schemas/openai/chat_completion_request.py +123 -0
- letta/schemas/openai/chat_completion_response.py +136 -0
- letta/schemas/openai/chat_completions.py +123 -0
- letta/schemas/openai/embedding_response.py +11 -0
- letta/schemas/openai/openai.py +157 -0
- letta/schemas/organization.py +20 -0
- letta/schemas/passage.py +80 -0
- letta/schemas/source.py +62 -0
- letta/schemas/tool.py +143 -0
- letta/schemas/usage.py +18 -0
- letta/schemas/user.py +33 -0
- letta/server/__init__.py +0 -0
- letta/server/constants.py +6 -0
- letta/server/rest_api/__init__.py +0 -0
- letta/server/rest_api/admin/__init__.py +0 -0
- letta/server/rest_api/admin/agents.py +21 -0
- letta/server/rest_api/admin/tools.py +83 -0
- letta/server/rest_api/admin/users.py +98 -0
- letta/server/rest_api/app.py +193 -0
- letta/server/rest_api/auth/__init__.py +0 -0
- letta/server/rest_api/auth/index.py +43 -0
- letta/server/rest_api/auth_token.py +22 -0
- letta/server/rest_api/interface.py +726 -0
- letta/server/rest_api/routers/__init__.py +0 -0
- letta/server/rest_api/routers/openai/__init__.py +0 -0
- letta/server/rest_api/routers/openai/assistants/__init__.py +0 -0
- letta/server/rest_api/routers/openai/assistants/assistants.py +115 -0
- letta/server/rest_api/routers/openai/assistants/schemas.py +121 -0
- letta/server/rest_api/routers/openai/assistants/threads.py +336 -0
- letta/server/rest_api/routers/openai/chat_completions/__init__.py +0 -0
- letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +131 -0
- letta/server/rest_api/routers/v1/__init__.py +15 -0
- letta/server/rest_api/routers/v1/agents.py +543 -0
- letta/server/rest_api/routers/v1/blocks.py +73 -0
- letta/server/rest_api/routers/v1/jobs.py +46 -0
- letta/server/rest_api/routers/v1/llms.py +28 -0
- letta/server/rest_api/routers/v1/organizations.py +61 -0
- letta/server/rest_api/routers/v1/sources.py +199 -0
- letta/server/rest_api/routers/v1/tools.py +103 -0
- letta/server/rest_api/routers/v1/users.py +109 -0
- letta/server/rest_api/static_files.py +74 -0
- letta/server/rest_api/utils.py +69 -0
- letta/server/server.py +1995 -0
- letta/server/startup.sh +8 -0
- letta/server/static_files/assets/index-0cbf7ad5.js +274 -0
- letta/server/static_files/assets/index-156816da.css +1 -0
- letta/server/static_files/assets/index-486e3228.js +274 -0
- letta/server/static_files/favicon.ico +0 -0
- letta/server/static_files/index.html +39 -0
- letta/server/static_files/memgpt_logo_transparent.png +0 -0
- letta/server/utils.py +46 -0
- letta/server/ws_api/__init__.py +0 -0
- letta/server/ws_api/example_client.py +104 -0
- letta/server/ws_api/interface.py +108 -0
- letta/server/ws_api/protocol.py +100 -0
- letta/server/ws_api/server.py +145 -0
- letta/settings.py +165 -0
- letta/streaming_interface.py +396 -0
- letta/system.py +207 -0
- letta/utils.py +1065 -0
- letta_nightly-0.1.7.dev20240924104148.dist-info/LICENSE +190 -0
- letta_nightly-0.1.7.dev20240924104148.dist-info/METADATA +98 -0
- letta_nightly-0.1.7.dev20240924104148.dist-info/RECORD +189 -0
- letta_nightly-0.1.7.dev20240924104148.dist-info/WHEEL +4 -0
- letta_nightly-0.1.7.dev20240924104148.dist-info/entry_points.txt +3 -0
letta/schemas/memory.py
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Dict, List, Optional
|
|
2
|
+
|
|
3
|
+
from jinja2 import Template, TemplateSyntaxError
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
# Forward referencing to avoid circular import with Agent -> Memory -> Agent
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from letta.agent import Agent
|
|
9
|
+
|
|
10
|
+
from letta.schemas.block import Block
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Memory(BaseModel, validate_assignment=True):
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
Represents the in-context memory of the agent. This includes both the `Block` objects (labelled by sections), as well as tools to edit the blocks.
|
|
17
|
+
|
|
18
|
+
Attributes:
|
|
19
|
+
memory (Dict[str, Block]): Mapping from memory block section to memory block.
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# Memory.memory is a dict mapping from memory block section to memory block.
|
|
24
|
+
memory: Dict[str, Block] = Field(default_factory=dict, description="Mapping from memory block section to memory block.")
|
|
25
|
+
|
|
26
|
+
# Memory.template is a Jinja2 template for compiling memory module into a prompt string.
|
|
27
|
+
prompt_template: str = Field(
|
|
28
|
+
default="{% for block in memory.values() %}"
|
|
29
|
+
'<{{ block.label }} characters="{{ block.value|length }}/{{ block.limit }}">\n'
|
|
30
|
+
"{{ block.value }}\n"
|
|
31
|
+
"</{{ block.label }}>"
|
|
32
|
+
"{% if not loop.last %}\n{% endif %}"
|
|
33
|
+
"{% endfor %}",
|
|
34
|
+
description="Jinja2 template for compiling memory blocks into a prompt string",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def get_prompt_template(self) -> str:
|
|
38
|
+
"""Return the current Jinja2 template string."""
|
|
39
|
+
return str(self.prompt_template)
|
|
40
|
+
|
|
41
|
+
def set_prompt_template(self, prompt_template: str):
|
|
42
|
+
"""
|
|
43
|
+
Set a new Jinja2 template string.
|
|
44
|
+
Validates the template syntax and compatibility with current memory structure.
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
# Validate Jinja2 syntax
|
|
48
|
+
Template(prompt_template)
|
|
49
|
+
|
|
50
|
+
# Validate compatibility with current memory structure
|
|
51
|
+
test_render = Template(prompt_template).render(memory=self.memory)
|
|
52
|
+
|
|
53
|
+
# If we get here, the template is valid and compatible
|
|
54
|
+
self.prompt_template = prompt_template
|
|
55
|
+
except TemplateSyntaxError as e:
|
|
56
|
+
raise ValueError(f"Invalid Jinja2 template syntax: {str(e)}")
|
|
57
|
+
except Exception as e:
|
|
58
|
+
raise ValueError(f"Prompt template is not compatible with current memory structure: {str(e)}")
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def load(cls, state: dict):
|
|
62
|
+
"""Load memory from dictionary object"""
|
|
63
|
+
obj = cls()
|
|
64
|
+
if len(state.keys()) == 2 and "memory" in state and "prompt_template" in state:
|
|
65
|
+
# New format
|
|
66
|
+
obj.prompt_template = state["prompt_template"]
|
|
67
|
+
for key, value in state["memory"].items():
|
|
68
|
+
obj.memory[key] = Block(**value)
|
|
69
|
+
else:
|
|
70
|
+
# Old format (pre-template)
|
|
71
|
+
for key, value in state.items():
|
|
72
|
+
obj.memory[key] = Block(**value)
|
|
73
|
+
return obj
|
|
74
|
+
|
|
75
|
+
def compile(self) -> str:
|
|
76
|
+
"""Generate a string representation of the memory in-context using the Jinja2 template"""
|
|
77
|
+
template = Template(self.prompt_template)
|
|
78
|
+
return template.render(memory=self.memory)
|
|
79
|
+
|
|
80
|
+
def to_dict(self):
|
|
81
|
+
"""Convert to dictionary representation"""
|
|
82
|
+
return {
|
|
83
|
+
"memory": {key: value.model_dump() for key, value in self.memory.items()},
|
|
84
|
+
"prompt_template": self.prompt_template,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
def to_flat_dict(self):
|
|
88
|
+
"""Convert to a dictionary that maps directly from block names to values"""
|
|
89
|
+
return {k: v.value for k, v in self.memory.items() if v is not None}
|
|
90
|
+
|
|
91
|
+
def list_block_names(self) -> List[str]:
|
|
92
|
+
"""Return a list of the block names held inside the memory object"""
|
|
93
|
+
return list(self.memory.keys())
|
|
94
|
+
|
|
95
|
+
# TODO: these should actually be label, not name
|
|
96
|
+
def get_block(self, name: str) -> Block:
|
|
97
|
+
"""Correct way to index into the memory.memory field, returns a Block"""
|
|
98
|
+
if name not in self.memory:
|
|
99
|
+
raise KeyError(f"Block field {name} does not exist (available sections = {', '.join(list(self.memory.keys()))})")
|
|
100
|
+
else:
|
|
101
|
+
return self.memory[name]
|
|
102
|
+
|
|
103
|
+
def get_blocks(self) -> List[Block]:
|
|
104
|
+
"""Return a list of the blocks held inside the memory object"""
|
|
105
|
+
return list(self.memory.values())
|
|
106
|
+
|
|
107
|
+
def link_block(self, name: str, block: Block, override: Optional[bool] = False):
|
|
108
|
+
"""Link a new block to the memory object"""
|
|
109
|
+
if not isinstance(block, Block):
|
|
110
|
+
raise ValueError(f"Param block must be type Block (not {type(block)})")
|
|
111
|
+
if not isinstance(name, str):
|
|
112
|
+
raise ValueError(f"Name must be str (not type {type(name)})")
|
|
113
|
+
if not override and name in self.memory:
|
|
114
|
+
raise ValueError(f"Block with name {name} already exists")
|
|
115
|
+
|
|
116
|
+
self.memory[name] = block
|
|
117
|
+
|
|
118
|
+
def update_block_value(self, name: str, value: str):
|
|
119
|
+
"""Update the value of a block"""
|
|
120
|
+
if name not in self.memory:
|
|
121
|
+
raise ValueError(f"Block with name {name} does not exist")
|
|
122
|
+
if not isinstance(value, str):
|
|
123
|
+
raise ValueError(f"Provided value must be a string")
|
|
124
|
+
|
|
125
|
+
self.memory[name].value = value
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# TODO: ideally this is refactored into ChatMemory and the subclasses are given more specific names.
|
|
129
|
+
class BasicBlockMemory(Memory):
|
|
130
|
+
"""
|
|
131
|
+
BasicBlockMemory is a basic implemention of the Memory class, which takes in a list of blocks and links them to the memory object. These are editable by the agent via the core memory functions.
|
|
132
|
+
|
|
133
|
+
Attributes:
|
|
134
|
+
memory (Dict[str, Block]): Mapping from memory block section to memory block.
|
|
135
|
+
|
|
136
|
+
Methods:
|
|
137
|
+
core_memory_append: Append to the contents of core memory.
|
|
138
|
+
core_memory_replace: Replace the contents of core memory.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
def __init__(self, blocks: List[Block] = []):
|
|
142
|
+
"""
|
|
143
|
+
Initialize the BasicBlockMemory object with a list of pre-defined blocks.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
blocks (List[Block]): List of blocks to be linked to the memory object.
|
|
147
|
+
"""
|
|
148
|
+
super().__init__()
|
|
149
|
+
for block in blocks:
|
|
150
|
+
# TODO: centralize these internal schema validations
|
|
151
|
+
# assert block.name is not None and block.name != "", "each existing chat block must have a name"
|
|
152
|
+
# self.link_block(name=block.name, block=block)
|
|
153
|
+
assert block.label is not None and block.label != "", "each existing chat block must have a name"
|
|
154
|
+
self.link_block(name=block.label, block=block)
|
|
155
|
+
|
|
156
|
+
def core_memory_append(self: "Agent", name: str, content: str) -> Optional[str]: # type: ignore
|
|
157
|
+
"""
|
|
158
|
+
Append to the contents of core memory.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
name (str): Section of the memory to be edited (persona or human).
|
|
162
|
+
content (str): Content to write to the memory. All unicode (including emojis) are supported.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Optional[str]: None is always returned as this function does not produce a response.
|
|
166
|
+
"""
|
|
167
|
+
current_value = str(self.memory.get_block(name).value)
|
|
168
|
+
new_value = current_value + "\n" + str(content)
|
|
169
|
+
self.memory.update_block_value(name=name, value=new_value)
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
def core_memory_replace(self: "Agent", name: str, old_content: str, new_content: str) -> Optional[str]: # type: ignore
|
|
173
|
+
"""
|
|
174
|
+
Replace the contents of core memory. To delete memories, use an empty string for new_content.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
name (str): Section of the memory to be edited (persona or human).
|
|
178
|
+
old_content (str): String to replace. Must be an exact match.
|
|
179
|
+
new_content (str): Content to write to the memory. All unicode (including emojis) are supported.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Optional[str]: None is always returned as this function does not produce a response.
|
|
183
|
+
"""
|
|
184
|
+
current_value = str(self.memory.get_block(name).value)
|
|
185
|
+
if old_content not in current_value:
|
|
186
|
+
raise ValueError(f"Old content '{old_content}' not found in memory block '{name}'")
|
|
187
|
+
new_value = current_value.replace(str(old_content), str(new_content))
|
|
188
|
+
self.memory.update_block_value(name=name, value=new_value)
|
|
189
|
+
return None
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class ChatMemory(BasicBlockMemory):
|
|
193
|
+
"""
|
|
194
|
+
ChatMemory initializes a BaseChatMemory with two default blocks, `human` and `persona`.
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
def __init__(self, persona: str, human: str, limit: int = 2000):
|
|
198
|
+
"""
|
|
199
|
+
Initialize the ChatMemory object with a persona and human string.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
persona (str): The starter value for the persona block.
|
|
203
|
+
human (str): The starter value for the human block.
|
|
204
|
+
limit (int): The character limit for each block.
|
|
205
|
+
"""
|
|
206
|
+
super().__init__()
|
|
207
|
+
self.link_block(name="persona", block=Block(name="persona", value=persona, limit=limit, label="persona"))
|
|
208
|
+
self.link_block(name="human", block=Block(name="human", value=human, limit=limit, label="human"))
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class UpdateMemory(BaseModel):
|
|
212
|
+
"""Update the memory of the agent"""
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class ArchivalMemorySummary(BaseModel):
|
|
216
|
+
size: int = Field(..., description="Number of rows in archival memory")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class RecallMemorySummary(BaseModel):
|
|
220
|
+
size: int = Field(..., description="Number of rows in recall memory")
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class CreateArchivalMemory(BaseModel):
|
|
224
|
+
text: str = Field(..., description="Text to write to archival memory.")
|