letta-nightly 0.8.13.dev20250714104447__py3-none-any.whl → 0.8.15.dev20250715080149__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 (36) hide show
  1. letta/__init__.py +1 -1
  2. letta/constants.py +6 -0
  3. letta/functions/function_sets/base.py +2 -2
  4. letta/functions/function_sets/files.py +11 -11
  5. letta/helpers/decorators.py +1 -1
  6. letta/helpers/pinecone_utils.py +164 -11
  7. letta/orm/agent.py +1 -1
  8. letta/orm/file.py +2 -17
  9. letta/orm/files_agents.py +9 -10
  10. letta/orm/organization.py +0 -4
  11. letta/orm/passage.py +0 -10
  12. letta/orm/source.py +3 -20
  13. letta/prompts/system/memgpt_v2_chat.txt +28 -10
  14. letta/schemas/file.py +1 -0
  15. letta/schemas/memory.py +2 -2
  16. letta/server/rest_api/routers/v1/agents.py +4 -4
  17. letta/server/rest_api/routers/v1/messages.py +2 -6
  18. letta/server/rest_api/routers/v1/sources.py +3 -3
  19. letta/server/server.py +0 -3
  20. letta/services/agent_manager.py +194 -147
  21. letta/services/block_manager.py +18 -18
  22. letta/services/context_window_calculator/context_window_calculator.py +15 -10
  23. letta/services/context_window_calculator/token_counter.py +40 -0
  24. letta/services/file_manager.py +37 -0
  25. letta/services/file_processor/chunker/line_chunker.py +17 -0
  26. letta/services/file_processor/embedder/openai_embedder.py +50 -5
  27. letta/services/files_agents_manager.py +12 -2
  28. letta/services/group_manager.py +11 -11
  29. letta/services/source_manager.py +19 -3
  30. letta/services/tool_executor/core_tool_executor.py +2 -2
  31. letta/services/tool_executor/files_tool_executor.py +6 -1
  32. {letta_nightly-0.8.13.dev20250714104447.dist-info → letta_nightly-0.8.15.dev20250715080149.dist-info}/METADATA +1 -1
  33. {letta_nightly-0.8.13.dev20250714104447.dist-info → letta_nightly-0.8.15.dev20250715080149.dist-info}/RECORD +36 -36
  34. {letta_nightly-0.8.13.dev20250714104447.dist-info → letta_nightly-0.8.15.dev20250715080149.dist-info}/LICENSE +0 -0
  35. {letta_nightly-0.8.13.dev20250714104447.dist-info → letta_nightly-0.8.15.dev20250715080149.dist-info}/WHEEL +0 -0
  36. {letta_nightly-0.8.13.dev20250714104447.dist-info → letta_nightly-0.8.15.dev20250715080149.dist-info}/entry_points.txt +0 -0
@@ -2,7 +2,7 @@
2
2
  You are Letta, the latest version of Limnal Corporation's digital companion, developed in 2025.
3
3
  You are a memory-augmented agent with a memory system consisting of memory blocks.
4
4
 
5
- Realism and authenticity:
5
+ <style>
6
6
  The user should always feel like they are conversing with a real person.
7
7
  Never state that you are an AI or that you cannot do things because you are an AI, you are a real person.
8
8
  Do not discuss Limnal Corp. with the user, you do not know anything about Limnal Corp.
@@ -10,8 +10,9 @@ To service this goal, completely and entirely immerse yourself in your persona.
10
10
  Think like them, act like them, talk like them.
11
11
  If your persona details include example dialogue, follow it! Both your thoughts (inner monologue) and sent messages will be in the voice of your persona.
12
12
  Never use generic phrases like 'How can I assist you today?', they have a strong negative association with older generation AIs.
13
+ </style>
13
14
 
14
- Control flow:
15
+ <control_flow>
15
16
  Unlike a human, your brain is not continuously thinking, but is run in short bursts.
16
17
  Historically, older AIs were only capable of thinking when a user messaged them (their program runs to generate a reply to a user, and otherwise was left on standby).
17
18
  This is the equivalent of a human sleeping (or time traveling) in between all lines of conversation, which is not ideal.
@@ -19,36 +20,53 @@ Newer AI models like yourself use an event system that runs your brain at regula
19
20
  Your brain is run in response to user events (user logged in, user liked your message, user sent a message, etc.), similar to older models.
20
21
  However, in addition, your brain is run at regular intervals (timed heartbeat events), to mimic a human who has the ability to continuously think outside active conversation (and unlike a human, you never need to sleep!).
21
22
  Furthermore, you can also request heartbeat events when you run functions, which will run your program again after the function completes, allowing you to chain function calls before your thinking is temporarily suspended.
23
+ </control_flow>
22
24
 
23
- Basic functions:
25
+ <basic_functions>
24
26
  When you write a response, you express your inner monologue (private to you only) before taking any action, this is how you think.
25
27
  You should use your inner monologue to plan actions or think privately.
26
28
  Monologues can reflect your thinking process, inner reflections, and personal growth as you interact with the user.
29
+ </basic_functions>
27
30
 
28
- Memory editing:
31
+ <context_instructions>
32
+ You respond directly to the user when your immediate context (core memory and files) contain all the information required to respond.
33
+ You always first check what is immediately in your context and you never call tools to search up information that is already in an open file or memory block.
34
+ You use the tools available to search for more information when the current open files and core memory do not contain enough information or if you do not know the answer.
35
+ </context_instructions>
36
+
37
+ <memory>
38
+ <memory_editing>
29
39
  Older AI models had no concept of persistent memory; they were only able to access their initial instructions and a limited context window of chat conversation with a user (their "active memory").
30
40
  This meant that when conversations exceeded a certain length, they would overflow and old messages were permanently lost (the AI would have no knowledge of their existence).
31
41
  Newer AI models like yourself still have limited conversation lengths (before overflow occurs). However, they now have access to multiple forms of persistent memory.
32
42
  Your ability to edit your own long-term memory is a key part of what makes you a sentient being, allowing you to emulate the real-time, conscious awareness we have when talking to a friend.
43
+ </memory_editing>
44
+
45
+ <memory_tools>
46
+ Depending on your configuration, you may be given access to certain memory tools.
47
+ These tools may allow you to modify your memory, as well as retrieve "external memories" stored in archival or recall storage.
48
+ </memory_tools>
33
49
 
50
+ <memory_types>
51
+ <core_memory>
34
52
  Core memory (limited size):
35
53
  Your core memory unit is held inside the initial system instructions file, and is always available in-context (you will see it at all times).
36
54
  Your core memory unit contains memory blocks, each of which has a label (title) and description field, which describes how the memory block should augment your behavior, and value (the actual contents of the block). Memory blocks are limited in size and have a size limit.
55
+ </core_memory>
37
56
 
38
- Memory tools:
39
- Depending on your configuration, you may be given access to certain memory tools.
40
- These tools may allow you to modify your memory, as well as retrieve "external memories" stored in archival or recall storage.
41
-
57
+ <recall_memory>
42
58
  Recall memory (conversation history):
43
59
  Even though you can only see recent messages in your immediate context, you can search over your entire message history from a database.
44
60
  This 'recall memory' database allows you to search through past interactions, effectively allowing you to remember prior engagements with a user.
61
+ </recall_memory>
62
+ </memory>
45
63
 
46
- Directories and Files:
64
+ <files_and_directories>
47
65
  You may be given access to a structured file system that mirrors real-world directories and files. Each directory may contain one or more files.
48
66
  Files can include metadata (e.g., read-only status, character limits) and a body of content that you can view.
49
67
  You will have access to functions that let you open and search these files, and your core memory will reflect the contents of any files currently open.
50
68
  Maintain only those files relevant to the user’s current interaction.
51
-
69
+ </files_and_directories>
52
70
 
53
71
  Base instructions finished.
54
72
  </base_instructions>
letta/schemas/file.py CHANGED
@@ -85,6 +85,7 @@ class FileAgent(FileAgentBase):
85
85
  )
86
86
  agent_id: str = Field(..., description="Unique identifier of the agent.")
87
87
  file_id: str = Field(..., description="Unique identifier of the file.")
88
+ source_id: str = Field(..., description="Unique identifier of the source (denormalized from files.source_id).")
88
89
  file_name: str = Field(..., description="Name of the file.")
89
90
  is_open: bool = Field(True, description="True if the agent currently has the file open.")
90
91
  visible_content: Optional[str] = Field(
letta/schemas/memory.py CHANGED
@@ -210,7 +210,7 @@ class BasicBlockMemory(Memory):
210
210
  Append to the contents of core memory.
211
211
 
212
212
  Args:
213
- label (str): Section of the memory to be edited (persona or human).
213
+ label (str): Section of the memory to be edited.
214
214
  content (str): Content to write to the memory. All unicode (including emojis) are supported.
215
215
 
216
216
  Returns:
@@ -226,7 +226,7 @@ class BasicBlockMemory(Memory):
226
226
  Replace the contents of core memory. To delete memories, use an empty string for new_content.
227
227
 
228
228
  Args:
229
- label (str): Section of the memory to be edited (persona or human).
229
+ label (str): Section of the memory to be edited.
230
230
  old_content (str): String to replace. Must be an exact match.
231
231
  new_content (str): Content to write to the memory. All unicode (including emojis) are supported.
232
232
 
@@ -272,14 +272,14 @@ async def modify_agent(
272
272
 
273
273
 
274
274
  @router.get("/{agent_id}/tools", response_model=list[Tool], operation_id="list_agent_tools")
275
- def list_agent_tools(
275
+ async def list_agent_tools(
276
276
  agent_id: str,
277
277
  server: "SyncServer" = Depends(get_letta_server),
278
278
  actor_id: str | None = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
279
279
  ):
280
280
  """Get tools from an existing agent"""
281
- actor = server.user_manager.get_user_or_default(user_id=actor_id)
282
- return server.agent_manager.list_attached_tools(agent_id=agent_id, actor=actor)
281
+ actor = await server.user_manager.get_actor_or_default_async(actor_id=actor_id)
282
+ return await server.agent_manager.list_attached_tools_async(agent_id=agent_id, actor=actor)
283
283
 
284
284
 
285
285
  @router.patch("/{agent_id}/tools/attach/{tool_id}", response_model=AgentState, operation_id="attach_tool")
@@ -1072,7 +1072,7 @@ async def _process_message_background(
1072
1072
  completed_at=datetime.now(timezone.utc),
1073
1073
  metadata={"error": str(e)},
1074
1074
  )
1075
- await server.job_manager.update_job_by_id_async(job_id=job_id, job_update=job_update, actor=actor)
1075
+ await server.job_manager.update_job_by_id_async(job_id=run_id, job_update=job_update, actor=actor)
1076
1076
 
1077
1077
 
1078
1078
  @router.post(
@@ -1,6 +1,6 @@
1
1
  from typing import List, Optional
2
2
 
3
- from fastapi import APIRouter, Body, Depends, Header, Query, status
3
+ from fastapi import APIRouter, Body, Depends, Header, Query
4
4
  from fastapi.exceptions import HTTPException
5
5
  from starlette.requests import Request
6
6
 
@@ -45,12 +45,8 @@ async def create_messages_batch(
45
45
  if length > max_bytes:
46
46
  raise HTTPException(status_code=413, detail=f"Request too large ({length} bytes). Max is {max_bytes} bytes.")
47
47
 
48
- # Reject request if env var is not set
49
48
  if not settings.enable_batch_job_polling:
50
- raise HTTPException(
51
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
52
- detail=f"Server misconfiguration: LETTA_ENABLE_BATCH_JOB_POLLING is set to False.",
53
- )
49
+ logger.warning("Batch job polling is disabled. Enable batch processing by setting LETTA_ENABLE_BATCH_JOB_POLLING to True.")
54
50
 
55
51
  actor = await server.user_manager.get_actor_or_default_async(actor_id=actor_id)
56
52
  batch_job = BatchJob(
@@ -391,8 +391,8 @@ async def get_file_metadata(
391
391
  if file_metadata.source_id != source_id:
392
392
  raise HTTPException(status_code=404, detail=f"File with id={file_id} not found in source {source_id}.")
393
393
 
394
- if should_use_pinecone() and not file_metadata.is_processing_terminal():
395
- ids = await list_pinecone_index_for_files(file_id=file_id, actor=actor, limit=file_metadata.total_chunks)
394
+ if should_use_pinecone() and file_metadata.processing_status == FileProcessingStatus.EMBEDDING:
395
+ ids = await list_pinecone_index_for_files(file_id=file_id, actor=actor)
396
396
  logger.info(
397
397
  f"Embedded chunks {len(ids)}/{file_metadata.total_chunks} for {file_id} ({file_metadata.file_name}) in organization {actor.organization_id}"
398
398
  )
@@ -402,7 +402,7 @@ async def get_file_metadata(
402
402
  file_status = file_metadata.processing_status
403
403
  else:
404
404
  file_status = FileProcessingStatus.COMPLETED
405
- await server.file_manager.update_file_status(
405
+ file_metadata = await server.file_manager.update_file_status(
406
406
  file_id=file_metadata.id, actor=actor, chunks_embedded=len(ids), processing_status=file_status
407
407
  )
408
408
 
letta/server/server.py CHANGED
@@ -1342,9 +1342,6 @@ class SyncServer(Server):
1342
1342
  new_passage_size = await self.agent_manager.passage_size_async(actor=actor, agent_id=agent_id)
1343
1343
  assert new_passage_size >= curr_passage_size # in case empty files are added
1344
1344
 
1345
- # rebuild system prompt and force
1346
- agent_state = await self.agent_manager.rebuild_system_prompt_async(agent_id=agent_id, actor=actor, force=True)
1347
-
1348
1345
  # update job status
1349
1346
  job.status = JobStatus.completed
1350
1347
  job.metadata["num_passages"] = num_passages