clinical-agent-memory-bench's picture
Upload 99 files
750b88d verified
Raw History Blame Contribute Delete
6.01 kB
--- a/letta/agent.py
+++ b/letta/agent.py
@@ -1,3 +1,4 @@
+# Modified.
import json
import time
import traceback
@@ -70,6 +71,33 @@
logger = get_logger(__name__)
+def _fit_context_window(sequence: List[Message], new_messages: List[Message], limit: Optional[int]) -> List[Message]:
+ if not limit or len(sequence) <= 2 or not new_messages:
+ return sequence
+ counts = get_token_counts_for_messages(sequence)
+ if sum(counts) <= limit:
+ return sequence
+ n_new = len(new_messages)
+ room = limit - counts[0] - sum(counts[-n_new:])
+ middle = list(zip(sequence[1:-n_new], counts[1:-n_new]))
+ units, i = [], 0
+ while i < len(middle):
+ j = i + 1
+ if getattr(middle[i][0], "role", None) == "assistant" and middle[i][0].tool_calls:
+ while j < len(middle) and getattr(middle[j][0], "role", None) == "tool":
+ j += 1
+ units.append(middle[i:j])
+ i = j
+ kept = []
+ for unit in reversed(units):
+ size = sum(n for _, n in unit)
+ if size > room:
+ break
+ kept[:0] = [m for m, _ in unit]
+ room -= size
+ return [sequence[0], *kept, *new_messages]
+
+
class BaseAgent(ABC):
"""
Abstract class for all agents.
@@ -745,6 +773,23 @@
elif max_chaining_steps is not None and counter > max_chaining_steps:
self.logger.info(f"Hit max chaining steps, stopping after {counter} steps")
break
+ elif (max_chaining_steps is not None and counter == max_chaining_steps
+ and (heartbeat_request or function_failed or token_warning)
+ and __import__("os").environ.get("MEMEBENCH_LETTA_FINAL_REPLY_AT_CAP") == "1"):
+ assert self.agent_state.created_by_id is not None
+ next_input_messages = [
+ Message.dict_to_message(
+ agent_id=self.agent_state.id,
+ model=self.model,
+ openai_message_dict={
+ "role": "user",
+ "content": get_heartbeat(
+ "You have reached the maximum number of steps. Call send_message now "
+ "with your final response."),
+ },
+ )
+ ]
+ continue
# Chain handlers
elif token_warning and summarizer_settings.send_memory_warning_message:
assert self.agent_state.created_by_id is not None
@@ -828,6 +873,8 @@
in_context_messages = self.agent_manager.get_in_context_messages(agent_id=self.agent_state.id, actor=self.user)
input_message_sequence = in_context_messages + messages
+ input_message_sequence = _fit_context_window(
+ input_message_sequence, messages, self.agent_state.llm_config.context_window)
if (
len(input_message_sequence) > 1
--- a/letta/constants.py
+++ b/letta/constants.py
@@ -1,7 +1,8 @@
+# Modified.
import os
from logging import CRITICAL, DEBUG, ERROR, INFO, NOTSET, WARN, WARNING
-LETTA_DIR = os.path.join(os.path.expanduser("~"), ".letta")
+LETTA_DIR = os.environ.get("LETTA_DIR") or os.path.join(os.path.expanduser("~"), ".letta")
LETTA_TOOL_EXECUTION_DIR = os.path.join(LETTA_DIR, "tool_execution_dir")
ADMIN_PREFIX = "/v1/admin"
--- a/letta/functions/function_sets/base.py
+++ b/letta/functions/function_sets/base.py
@@ -1,3 +1,4 @@
+# Modified.
from typing import Optional
from letta.agent import Agent
@@ -43,7 +44,7 @@
page = int(page)
except:
raise ValueError(f"'page' argument must be an integer")
- count = RETRIEVAL_QUERY_DEFAULT_PAGE_SIZE
+ count = (self.agent_state.metadata or {}).get("retrieve_num", RETRIEVAL_QUERY_DEFAULT_PAGE_SIZE)
# TODO: add paging by page number. currently cursor only works with strings.
# original: start=page * count
messages = self.message_manager.list_user_messages_for_agent(
@@ -104,7 +105,7 @@
page = int(page)
except:
raise ValueError(f"'page' argument must be an integer")
- count = RETRIEVAL_QUERY_DEFAULT_PAGE_SIZE
+ count = (self.agent_state.metadata or {}).get("retrieve_num", RETRIEVAL_QUERY_DEFAULT_PAGE_SIZE)
try:
# Get results using passage manager
--- a/letta/schemas/openai/chat_completion_request.py
+++ b/letta/schemas/openai/chat_completion_request.py
@@ -1,3 +1,4 @@
+# Modified.
from typing import Any, Dict, List, Literal, Optional, Union
from pydantic import BaseModel, Field, field_validator
@@ -124,6 +125,7 @@
logprobs: Optional[bool] = False
top_logprobs: Optional[int] = None
max_tokens: Optional[int] = None
+ max_completion_tokens: Optional[int] = None
n: Optional[int] = 1
presence_penalty: Optional[float] = 0
response_format: Optional[ResponseFormat] = None
--- a/letta/services/message_manager.py
+++ b/letta/services/message_manager.py
@@ -1,7 +1,8 @@
+# Modified.
import json
from typing import List, Optional, Sequence
-from sqlalchemy import delete, exists, func, select, text
+from sqlalchemy import String, cast, delete, exists, func, select, text
from letta.log import get_logger
from letta.orm.agent import Agent as AgentModel
@@ -304,7 +305,9 @@
query = query.filter(MessageModel.group_id == group_id)
# If query_text is provided, filter messages using subquery + json_array_elements.
- if query_text:
+ if query_text and session.bind is not None and session.bind.dialect.name == "sqlite":
+ query = query.filter(func.lower(cast(MessageModel.content, String)).like(f"%{query_text.lower()}%"))
+ elif query_text:
content_element = func.json_array_elements(MessageModel.content).alias("content_element")
query = query.filter(
exists(