letta-nightly 0.4.1.dev20241008104105__py3-none-any.whl → 0.4.1.dev20241010104112__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 +18 -2
- letta/agent_store/db.py +23 -7
- letta/cli/cli.py +2 -1
- letta/cli/cli_config.py +1 -1098
- letta/client/client.py +8 -1
- letta/client/utils.py +7 -2
- letta/credentials.py +2 -2
- letta/embeddings.py +3 -0
- letta/functions/schema_generator.py +1 -1
- letta/interface.py +6 -2
- letta/llm_api/anthropic.py +3 -24
- letta/llm_api/azure_openai.py +47 -98
- letta/llm_api/azure_openai_constants.py +10 -0
- letta/llm_api/google_ai.py +38 -63
- letta/llm_api/helpers.py +64 -2
- letta/llm_api/llm_api_tools.py +6 -15
- letta/llm_api/openai.py +6 -49
- letta/local_llm/constants.py +3 -0
- letta/main.py +1 -1
- letta/metadata.py +2 -0
- letta/providers.py +165 -31
- letta/schemas/agent.py +14 -0
- letta/schemas/llm_config.py +0 -3
- letta/schemas/openai/chat_completion_response.py +3 -0
- letta/schemas/tool.py +3 -3
- letta/server/rest_api/routers/openai/assistants/threads.py +5 -5
- letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +2 -2
- letta/server/rest_api/routers/v1/agents.py +11 -11
- letta/server/rest_api/routers/v1/blocks.py +2 -2
- letta/server/rest_api/routers/v1/jobs.py +2 -2
- letta/server/rest_api/routers/v1/sources.py +12 -12
- letta/server/rest_api/routers/v1/tools.py +6 -6
- letta/server/server.py +26 -7
- letta/settings.py +3 -112
- letta/streaming_interface.py +8 -4
- {letta_nightly-0.4.1.dev20241008104105.dist-info → letta_nightly-0.4.1.dev20241010104112.dist-info}/METADATA +1 -1
- {letta_nightly-0.4.1.dev20241008104105.dist-info → letta_nightly-0.4.1.dev20241010104112.dist-info}/RECORD +40 -42
- letta/configs/anthropic.json +0 -13
- letta/configs/letta_hosted.json +0 -11
- letta/configs/openai.json +0 -12
- {letta_nightly-0.4.1.dev20241008104105.dist-info → letta_nightly-0.4.1.dev20241010104112.dist-info}/LICENSE +0 -0
- {letta_nightly-0.4.1.dev20241008104105.dist-info → letta_nightly-0.4.1.dev20241010104112.dist-info}/WHEEL +0 -0
- {letta_nightly-0.4.1.dev20241008104105.dist-info → letta_nightly-0.4.1.dev20241010104112.dist-info}/entry_points.txt +0 -0
letta/agent.py
CHANGED
|
@@ -239,6 +239,7 @@ class Agent(BaseAgent):
|
|
|
239
239
|
assert isinstance(self.agent_state.memory, Memory), f"Memory object is not of type Memory: {type(self.agent_state.memory)}"
|
|
240
240
|
|
|
241
241
|
# link tools
|
|
242
|
+
self.tools = tools
|
|
242
243
|
self.link_tools(tools)
|
|
243
244
|
|
|
244
245
|
# gpt-4, gpt-3.5-turbo, ...
|
|
@@ -338,6 +339,9 @@ class Agent(BaseAgent):
|
|
|
338
339
|
for tool_name in self.agent_state.tools:
|
|
339
340
|
assert tool_name in [tool.name for tool in tools], f"Tool name {tool_name} not included in agent tool list"
|
|
340
341
|
|
|
342
|
+
# Update tools
|
|
343
|
+
self.tools = tools
|
|
344
|
+
|
|
341
345
|
# Store the functions schemas (this is passed as an argument to ChatCompletion)
|
|
342
346
|
self.functions = []
|
|
343
347
|
self.functions_python = {}
|
|
@@ -482,7 +486,7 @@ class Agent(BaseAgent):
|
|
|
482
486
|
inner_thoughts_in_kwargs_option=inner_thoughts_in_kwargs_option,
|
|
483
487
|
)
|
|
484
488
|
|
|
485
|
-
if len(response.choices) == 0:
|
|
489
|
+
if len(response.choices) == 0 or response.choices[0] is None:
|
|
486
490
|
raise Exception(f"API call didn't return a message: {response}")
|
|
487
491
|
|
|
488
492
|
# special case for 'length'
|
|
@@ -552,9 +556,12 @@ class Agent(BaseAgent):
|
|
|
552
556
|
) # extend conversation with assistant's reply
|
|
553
557
|
printd(f"Function call message: {messages[-1]}")
|
|
554
558
|
|
|
559
|
+
nonnull_content = False
|
|
555
560
|
if response_message.content:
|
|
556
561
|
# The content if then internal monologue, not chat
|
|
557
562
|
self.interface.internal_monologue(response_message.content, msg_obj=messages[-1])
|
|
563
|
+
# Flag to avoid printing a duplicate if inner thoughts get popped from the function call
|
|
564
|
+
nonnull_content = True
|
|
558
565
|
|
|
559
566
|
# Step 3: call the function
|
|
560
567
|
# Note: the JSON response may not always be valid; be sure to handle errors
|
|
@@ -615,12 +622,17 @@ class Agent(BaseAgent):
|
|
|
615
622
|
if "inner_thoughts" in function_args:
|
|
616
623
|
response_message.content = function_args.pop("inner_thoughts")
|
|
617
624
|
# The content if then internal monologue, not chat
|
|
618
|
-
if response_message.content:
|
|
625
|
+
if response_message.content and not nonnull_content:
|
|
619
626
|
self.interface.internal_monologue(response_message.content, msg_obj=messages[-1])
|
|
620
627
|
|
|
621
628
|
# (Still parsing function args)
|
|
622
629
|
# Handle requests for immediate heartbeat
|
|
623
630
|
heartbeat_request = function_args.pop("request_heartbeat", None)
|
|
631
|
+
|
|
632
|
+
# Edge case: heartbeat_request is returned as a stringified boolean, we will attempt to parse:
|
|
633
|
+
if isinstance(heartbeat_request, str) and heartbeat_request.lower().strip() == "true":
|
|
634
|
+
heartbeat_request = True
|
|
635
|
+
|
|
624
636
|
if not isinstance(heartbeat_request, bool) or heartbeat_request is None:
|
|
625
637
|
printd(
|
|
626
638
|
f"{CLI_WARNING_PREFIX}'request_heartbeat' arg parsed was not a bool or None, type={type(heartbeat_request)}, value={heartbeat_request}"
|
|
@@ -1353,6 +1365,10 @@ def save_agent(agent: Agent, ms: MetadataStore):
|
|
|
1353
1365
|
else:
|
|
1354
1366
|
ms.create_agent(agent_state)
|
|
1355
1367
|
|
|
1368
|
+
for tool in agent.tools:
|
|
1369
|
+
if ms.get_tool(tool_name=tool.name, user_id=tool.user_id) is None:
|
|
1370
|
+
ms.create_tool(tool)
|
|
1371
|
+
|
|
1356
1372
|
agent.agent_state = ms.get_agent(agent_id=agent_id)
|
|
1357
1373
|
assert isinstance(agent.agent_state.memory, Memory), f"Memory is not a Memory object: {type(agent_state.memory)}"
|
|
1358
1374
|
|
letta/agent_store/db.py
CHANGED
|
@@ -398,8 +398,6 @@ class PostgresStorageConnector(SQLStorageConnector):
|
|
|
398
398
|
return records
|
|
399
399
|
|
|
400
400
|
def insert_many(self, records, exists_ok=True, show_progress=False):
|
|
401
|
-
pass
|
|
402
|
-
|
|
403
401
|
# TODO: this is terrible, should eventually be done the same way for all types (migrate to SQLModel)
|
|
404
402
|
if len(records) == 0:
|
|
405
403
|
return
|
|
@@ -506,18 +504,36 @@ class SQLLiteStorageConnector(SQLStorageConnector):
|
|
|
506
504
|
# sqlite3.register_converter("UUID", lambda b: uuid.UUID(bytes_le=b))
|
|
507
505
|
|
|
508
506
|
def insert_many(self, records, exists_ok=True, show_progress=False):
|
|
509
|
-
pass
|
|
510
|
-
|
|
511
507
|
# TODO: this is terrible, should eventually be done the same way for all types (migrate to SQLModel)
|
|
512
508
|
if len(records) == 0:
|
|
513
509
|
return
|
|
510
|
+
|
|
511
|
+
added_ids = [] # avoid adding duplicates
|
|
512
|
+
# NOTE: this has not great performance due to the excessive commits
|
|
514
513
|
with self.session_maker() as session:
|
|
515
514
|
iterable = tqdm(records) if show_progress else records
|
|
516
515
|
for record in iterable:
|
|
517
516
|
# db_record = self.db_model(**vars(record))
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
517
|
+
|
|
518
|
+
if record.id in added_ids:
|
|
519
|
+
continue
|
|
520
|
+
|
|
521
|
+
existing_record = session.query(self.db_model).filter_by(id=record.id).first()
|
|
522
|
+
if existing_record:
|
|
523
|
+
if exists_ok:
|
|
524
|
+
fields = record.model_dump()
|
|
525
|
+
fields.pop("id")
|
|
526
|
+
session.query(self.db_model).filter(self.db_model.id == record.id).update(fields)
|
|
527
|
+
session.commit()
|
|
528
|
+
else:
|
|
529
|
+
raise ValueError(f"Record with id {record.id} already exists.")
|
|
530
|
+
|
|
531
|
+
else:
|
|
532
|
+
db_record = self.db_model(**record.dict())
|
|
533
|
+
session.add(db_record)
|
|
534
|
+
session.commit()
|
|
535
|
+
|
|
536
|
+
added_ids.append(record.id)
|
|
521
537
|
|
|
522
538
|
def insert(self, record, exists_ok=True):
|
|
523
539
|
self.insert_many([record], exists_ok=exists_ok)
|
letta/cli/cli.py
CHANGED
|
@@ -11,6 +11,7 @@ from letta import create_client
|
|
|
11
11
|
from letta.agent import Agent, save_agent
|
|
12
12
|
from letta.config import LettaConfig
|
|
13
13
|
from letta.constants import CLI_WARNING_PREFIX, LETTA_DIR
|
|
14
|
+
from letta.local_llm.constants import ASSISTANT_MESSAGE_CLI_SYMBOL
|
|
14
15
|
from letta.log import get_logger
|
|
15
16
|
from letta.metadata import MetadataStore
|
|
16
17
|
from letta.schemas.enums import OptionState
|
|
@@ -276,7 +277,7 @@ def run(
|
|
|
276
277
|
memory = ChatMemory(human=human_obj.value, persona=persona_obj.value, limit=core_memory_limit)
|
|
277
278
|
metadata = {"human": human_obj.name, "persona": persona_obj.name}
|
|
278
279
|
|
|
279
|
-
typer.secho(f"->
|
|
280
|
+
typer.secho(f"-> {ASSISTANT_MESSAGE_CLI_SYMBOL} Using persona profile: '{persona_obj.name}'", fg=typer.colors.WHITE)
|
|
280
281
|
typer.secho(f"-> 🧑 Using human profile: '{human_obj.name}'", fg=typer.colors.WHITE)
|
|
281
282
|
|
|
282
283
|
# add tools
|