letta-nightly 0.5.0.dev20241016104103__py3-none-any.whl → 0.5.0.dev20241018104142__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 +3 -12
- letta/cli/cli.py +0 -2
- letta/constants.py +1 -1
- letta/functions/helpers.py +3 -3
- letta/llm_api/anthropic.py +1 -1
- letta/llm_api/helpers.py +0 -15
- letta/llm_api/llm_api_tools.py +35 -47
- letta/llm_api/openai.py +2 -3
- letta/local_llm/llm_chat_completion_wrappers/chatml.py +1 -1
- letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +1 -1
- letta/main.py +0 -4
- letta/metadata.py +5 -1
- letta/o1_agent.py +87 -0
- letta/personas/examples/o1_persona.txt +5 -0
- letta/prompts/system/memgpt_modified_o1.txt +31 -0
- letta/schemas/agent.py +30 -2
- letta/schemas/llm_config.py +24 -1
- letta/schemas/tool.py +34 -2
- letta/server/server.py +49 -33
- letta/server/static_files/assets/{index-dc228d4a.js → index-d6b3669a.js} +59 -59
- letta/server/static_files/index.html +1 -1
- letta/settings.py +3 -0
- {letta_nightly-0.5.0.dev20241016104103.dist-info → letta_nightly-0.5.0.dev20241018104142.dist-info}/METADATA +1 -1
- {letta_nightly-0.5.0.dev20241016104103.dist-info → letta_nightly-0.5.0.dev20241018104142.dist-info}/RECORD +27 -24
- {letta_nightly-0.5.0.dev20241016104103.dist-info → letta_nightly-0.5.0.dev20241018104142.dist-info}/LICENSE +0 -0
- {letta_nightly-0.5.0.dev20241016104103.dist-info → letta_nightly-0.5.0.dev20241018104142.dist-info}/WHEEL +0 -0
- {letta_nightly-0.5.0.dev20241016104103.dist-info → letta_nightly-0.5.0.dev20241018104142.dist-info}/entry_points.txt +0 -0
letta/schemas/llm_config.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Literal, Optional
|
|
2
2
|
|
|
3
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field, root_validator
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class LLMConfig(BaseModel):
|
|
@@ -13,6 +13,7 @@ class LLMConfig(BaseModel):
|
|
|
13
13
|
model_endpoint (str): The endpoint for the model.
|
|
14
14
|
model_wrapper (str): The wrapper for the model. This is used to wrap additional text around the input/output of the model. This is useful for text-to-text completions, such as the Completions API in OpenAI.
|
|
15
15
|
context_window (int): The context window size for the model.
|
|
16
|
+
put_inner_thoughts_in_kwargs (bool): Puts 'inner_thoughts' as a kwarg in the function call if this is set to True. This helps with function calling performance and also the generation of inner thoughts.
|
|
16
17
|
"""
|
|
17
18
|
|
|
18
19
|
# TODO: 🤮 don't default to a vendor! bug city!
|
|
@@ -38,10 +39,32 @@ class LLMConfig(BaseModel):
|
|
|
38
39
|
model_endpoint: Optional[str] = Field(None, description="The endpoint for the model.")
|
|
39
40
|
model_wrapper: Optional[str] = Field(None, description="The wrapper for the model.")
|
|
40
41
|
context_window: int = Field(..., description="The context window size for the model.")
|
|
42
|
+
put_inner_thoughts_in_kwargs: Optional[bool] = Field(
|
|
43
|
+
True,
|
|
44
|
+
description="Puts 'inner_thoughts' as a kwarg in the function call if this is set to True. This helps with function calling performance and also the generation of inner thoughts.",
|
|
45
|
+
)
|
|
41
46
|
|
|
42
47
|
# FIXME hack to silence pydantic protected namespace warning
|
|
43
48
|
model_config = ConfigDict(protected_namespaces=())
|
|
44
49
|
|
|
50
|
+
@root_validator(pre=True)
|
|
51
|
+
def set_default_put_inner_thoughts(cls, values):
|
|
52
|
+
"""
|
|
53
|
+
Dynamically set the default for put_inner_thoughts_in_kwargs based on the model field,
|
|
54
|
+
falling back to True if no specific rule is defined.
|
|
55
|
+
"""
|
|
56
|
+
model = values.get("model")
|
|
57
|
+
|
|
58
|
+
# Define models where we want put_inner_thoughts_in_kwargs to be False
|
|
59
|
+
# For now it is gpt-4
|
|
60
|
+
avoid_put_inner_thoughts_in_kwargs = ["gpt-4"]
|
|
61
|
+
|
|
62
|
+
# Only modify the value if it's None or not provided
|
|
63
|
+
if values.get("put_inner_thoughts_in_kwargs") is None:
|
|
64
|
+
values["put_inner_thoughts_in_kwargs"] = False if model in avoid_put_inner_thoughts_in_kwargs else True
|
|
65
|
+
|
|
66
|
+
return values
|
|
67
|
+
|
|
45
68
|
@classmethod
|
|
46
69
|
def default_config(cls, model_name: str):
|
|
47
70
|
if model_name == "gpt-4":
|
letta/schemas/tool.py
CHANGED
|
@@ -112,11 +112,11 @@ class Tool(BaseTool):
|
|
|
112
112
|
Class method to create an instance of Tool from a Langchain tool (must be from langchain_community.tools).
|
|
113
113
|
|
|
114
114
|
Args:
|
|
115
|
-
langchain_tool (LangChainBaseTool): An instance of a
|
|
115
|
+
langchain_tool (LangChainBaseTool): An instance of a LangChain BaseTool (BaseTool from LangChain)
|
|
116
116
|
additional_imports_module_attr_map (dict[str, str]): A mapping of module names to attribute name. This is used internally to import all the required classes for the langchain tool. For example, you would pass in `{"langchain_community.utilities": "WikipediaAPIWrapper"}` for `from langchain_community.tools import WikipediaQueryRun`. NOTE: You do NOT need to specify the tool import here, that is done automatically for you.
|
|
117
117
|
|
|
118
118
|
Returns:
|
|
119
|
-
Tool: A Letta Tool initialized with attributes derived from the provided
|
|
119
|
+
Tool: A Letta Tool initialized with attributes derived from the provided LangChain BaseTool object.
|
|
120
120
|
"""
|
|
121
121
|
description = langchain_tool.description
|
|
122
122
|
source_type = "python"
|
|
@@ -174,6 +174,38 @@ class Tool(BaseTool):
|
|
|
174
174
|
json_schema=json_schema,
|
|
175
175
|
)
|
|
176
176
|
|
|
177
|
+
@classmethod
|
|
178
|
+
def load_default_langchain_tools(cls) -> List["Tool"]:
|
|
179
|
+
# For now, we only support wikipedia tool
|
|
180
|
+
from langchain_community.tools import WikipediaQueryRun
|
|
181
|
+
from langchain_community.utilities import WikipediaAPIWrapper
|
|
182
|
+
|
|
183
|
+
wikipedia_tool = Tool.from_langchain(
|
|
184
|
+
WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()), {"langchain_community.utilities": "WikipediaAPIWrapper"}
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
return [wikipedia_tool]
|
|
188
|
+
|
|
189
|
+
@classmethod
|
|
190
|
+
def load_default_crewai_tools(cls) -> List["Tool"]:
|
|
191
|
+
# For now, we only support scrape website tool
|
|
192
|
+
from crewai_tools import ScrapeWebsiteTool
|
|
193
|
+
|
|
194
|
+
web_scrape_tool = Tool.from_crewai(ScrapeWebsiteTool())
|
|
195
|
+
|
|
196
|
+
return [web_scrape_tool]
|
|
197
|
+
|
|
198
|
+
@classmethod
|
|
199
|
+
def load_default_composio_tools(cls) -> List["Tool"]:
|
|
200
|
+
from composio_langchain import Action
|
|
201
|
+
|
|
202
|
+
calculator = Tool.get_composio_tool(action=Action.MATHEMATICAL_CALCULATOR)
|
|
203
|
+
serp_news = Tool.get_composio_tool(action=Action.SERPAPI_NEWS_SEARCH)
|
|
204
|
+
serp_google_search = Tool.get_composio_tool(action=Action.SERPAPI_SEARCH)
|
|
205
|
+
serp_google_maps = Tool.get_composio_tool(action=Action.SERPAPI_GOOGLE_MAPS_SEARCH)
|
|
206
|
+
|
|
207
|
+
return [calculator, serp_news, serp_google_search, serp_google_maps]
|
|
208
|
+
|
|
177
209
|
|
|
178
210
|
class ToolCreate(BaseTool):
|
|
179
211
|
id: Optional[str] = Field(None, description="The unique identifier of the tool. If this is not provided, it will be autogenerated.")
|
letta/server/server.py
CHANGED
|
@@ -43,12 +43,12 @@ from letta.interface import CLIInterface # for printing to terminal
|
|
|
43
43
|
from letta.log import get_logger
|
|
44
44
|
from letta.memory import get_memory_functions
|
|
45
45
|
from letta.metadata import Base, MetadataStore
|
|
46
|
+
from letta.o1_agent import O1Agent
|
|
46
47
|
from letta.prompts import gpt_system
|
|
47
48
|
from letta.providers import (
|
|
48
49
|
AnthropicProvider,
|
|
49
50
|
AzureProvider,
|
|
50
51
|
GoogleAIProvider,
|
|
51
|
-
GroqProvider,
|
|
52
52
|
LettaProvider,
|
|
53
53
|
OllamaProvider,
|
|
54
54
|
OpenAIProvider,
|
|
@@ -73,12 +73,7 @@ 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
|
|
77
|
-
ArchivalMemorySummary,
|
|
78
|
-
ContextWindowOverview,
|
|
79
|
-
Memory,
|
|
80
|
-
RecallMemorySummary,
|
|
81
|
-
)
|
|
76
|
+
from letta.schemas.memory import ArchivalMemorySummary, Memory, RecallMemorySummary
|
|
82
77
|
from letta.schemas.message import Message, MessageCreate, MessageRole, UpdateMessage
|
|
83
78
|
from letta.schemas.organization import Organization, OrganizationCreate
|
|
84
79
|
from letta.schemas.passage import Passage
|
|
@@ -249,6 +244,9 @@ class SyncServer(Server):
|
|
|
249
244
|
# add global default tools (for admin)
|
|
250
245
|
self.add_default_tools(module_name="base")
|
|
251
246
|
|
|
247
|
+
if settings.load_default_external_tools:
|
|
248
|
+
self.add_default_external_tools()
|
|
249
|
+
|
|
252
250
|
# collect providers (always has Letta as a default)
|
|
253
251
|
self._enabled_providers: List[Provider] = [LettaProvider()]
|
|
254
252
|
if model_settings.openai_api_key:
|
|
@@ -303,12 +301,6 @@ class SyncServer(Server):
|
|
|
303
301
|
base_url=model_settings.vllm_api_base,
|
|
304
302
|
)
|
|
305
303
|
)
|
|
306
|
-
if model_settings.groq_api_key:
|
|
307
|
-
self._enabled_providers.append(
|
|
308
|
-
GroqProvider(
|
|
309
|
-
api_key=model_settings.groq_api_key,
|
|
310
|
-
)
|
|
311
|
-
)
|
|
312
304
|
|
|
313
305
|
def save_agents(self):
|
|
314
306
|
"""Saves all the agents that are in the in-memory object store"""
|
|
@@ -373,8 +365,10 @@ class SyncServer(Server):
|
|
|
373
365
|
|
|
374
366
|
if agent_state.agent_type == AgentType.memgpt_agent:
|
|
375
367
|
letta_agent = Agent(agent_state=agent_state, interface=interface, tools=tool_objs)
|
|
368
|
+
elif agent_state.agent_type == AgentType.o1_agent:
|
|
369
|
+
letta_agent = O1Agent(agent_state=agent_state, interface=interface, tools=tool_objs)
|
|
376
370
|
else:
|
|
377
|
-
raise NotImplementedError("
|
|
371
|
+
raise NotImplementedError("Not a supported agent type")
|
|
378
372
|
|
|
379
373
|
# Add the agent to the in-memory store and return its reference
|
|
380
374
|
logger.debug(f"Adding agent to the agent cache: user_id={user_id}, agent_id={agent_id}")
|
|
@@ -806,10 +800,18 @@ class SyncServer(Server):
|
|
|
806
800
|
if request.name is None:
|
|
807
801
|
request.name = create_random_username()
|
|
808
802
|
|
|
803
|
+
if request.agent_type is None:
|
|
804
|
+
request.agent_type = AgentType.memgpt_agent
|
|
805
|
+
|
|
809
806
|
# system debug
|
|
810
807
|
if request.system is None:
|
|
811
808
|
# TODO: don't hardcode
|
|
812
|
-
request.
|
|
809
|
+
if request.agent_type == AgentType.memgpt_agent:
|
|
810
|
+
request.system = gpt_system.get_system_text("memgpt_chat")
|
|
811
|
+
elif request.agent_type == AgentType.o1_agent:
|
|
812
|
+
request.system = gpt_system.get_system_text("memgpt_modified_o1")
|
|
813
|
+
else:
|
|
814
|
+
raise ValueError(f"Invalid agent type: {request.agent_type}")
|
|
813
815
|
|
|
814
816
|
logger.debug(f"Attempting to find user: {user_id}")
|
|
815
817
|
user = self.ms.get_user(user_id=user_id)
|
|
@@ -869,13 +871,22 @@ class SyncServer(Server):
|
|
|
869
871
|
description=request.description,
|
|
870
872
|
metadata_=request.metadata_,
|
|
871
873
|
)
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
874
|
+
if request.agent_type == AgentType.memgpt_agent:
|
|
875
|
+
agent = Agent(
|
|
876
|
+
interface=interface,
|
|
877
|
+
agent_state=agent_state,
|
|
878
|
+
tools=tool_objs,
|
|
879
|
+
# gpt-3.5-turbo tends to omit inner monologue, relax this requirement for now
|
|
880
|
+
first_message_verify_mono=True if (llm_config.model is not None and "gpt-4" in llm_config.model) else False,
|
|
881
|
+
)
|
|
882
|
+
elif request.agent_type == AgentType.o1_agent:
|
|
883
|
+
agent = O1Agent(
|
|
884
|
+
interface=interface,
|
|
885
|
+
agent_state=agent_state,
|
|
886
|
+
tools=tool_objs,
|
|
887
|
+
# gpt-3.5-turbo tends to omit inner monologue, relax this requirement for now
|
|
888
|
+
first_message_verify_mono=True if (llm_config.model is not None and "gpt-4" in llm_config.model) else False,
|
|
889
|
+
)
|
|
879
890
|
# rebuilding agent memory on agent create in case shared memory blocks
|
|
880
891
|
# were specified in the new agent's memory config. we're doing this for two reasons:
|
|
881
892
|
# 1. if only the ID of the shared memory block was specified, we can fetch its most recent value
|
|
@@ -1453,7 +1464,6 @@ class SyncServer(Server):
|
|
|
1453
1464
|
# Get the agent object (loaded in memory)
|
|
1454
1465
|
letta_agent = self._get_or_load_agent(agent_id=agent_id)
|
|
1455
1466
|
assert isinstance(letta_agent.memory, Memory)
|
|
1456
|
-
assert isinstance(letta_agent.agent_state.memory, Memory)
|
|
1457
1467
|
return letta_agent.agent_state.model_copy(deep=True)
|
|
1458
1468
|
|
|
1459
1469
|
def get_server_config(self, include_defaults: bool = False) -> dict:
|
|
@@ -1969,11 +1979,13 @@ class SyncServer(Server):
|
|
|
1969
1979
|
# Handle other general exceptions
|
|
1970
1980
|
raise e
|
|
1971
1981
|
|
|
1982
|
+
functions_to_schema = []
|
|
1972
1983
|
try:
|
|
1973
1984
|
# Load the function set
|
|
1974
1985
|
functions_to_schema = load_function_set(module)
|
|
1975
1986
|
except ValueError as e:
|
|
1976
1987
|
err = f"Error loading function set '{module_name}': {e}"
|
|
1988
|
+
warnings.warn(err)
|
|
1977
1989
|
|
|
1978
1990
|
# create tool in db
|
|
1979
1991
|
for name, schema in functions_to_schema.items():
|
|
@@ -1997,6 +2009,20 @@ class SyncServer(Server):
|
|
|
1997
2009
|
update=True,
|
|
1998
2010
|
)
|
|
1999
2011
|
|
|
2012
|
+
def add_default_external_tools(self, user_id: Optional[str] = None) -> bool:
|
|
2013
|
+
"""Add default langchain tools. Return true if successful, false otherwise."""
|
|
2014
|
+
success = True
|
|
2015
|
+
tools = Tool.load_default_langchain_tools() + Tool.load_default_crewai_tools() + Tool.load_default_composio_tools()
|
|
2016
|
+
for tool in tools:
|
|
2017
|
+
try:
|
|
2018
|
+
self.ms.create_tool(tool)
|
|
2019
|
+
except Exception as e:
|
|
2020
|
+
warnings.warn(f"An error occurred while creating tool {tool}: {e}")
|
|
2021
|
+
warnings.warn(traceback.format_exc())
|
|
2022
|
+
success = False
|
|
2023
|
+
|
|
2024
|
+
return success
|
|
2025
|
+
|
|
2000
2026
|
def add_default_blocks(self, user_id: str):
|
|
2001
2027
|
from letta.utils import list_human_files, list_persona_files
|
|
2002
2028
|
|
|
@@ -2140,13 +2166,3 @@ class SyncServer(Server):
|
|
|
2140
2166
|
|
|
2141
2167
|
def add_embedding_model(self, request: EmbeddingConfig) -> EmbeddingConfig:
|
|
2142
2168
|
"""Add a new embedding model"""
|
|
2143
|
-
|
|
2144
|
-
def get_agent_context_window(
|
|
2145
|
-
self,
|
|
2146
|
-
user_id: str,
|
|
2147
|
-
agent_id: str,
|
|
2148
|
-
) -> ContextWindowOverview:
|
|
2149
|
-
|
|
2150
|
-
# Get the current message
|
|
2151
|
-
letta_agent = self._get_or_load_agent(agent_id=agent_id)
|
|
2152
|
-
return letta_agent.get_context_window()
|