fix: add more timezone fixes (#3025)

This commit is contained in:
Sarah Wooders
2025-06-25 14:51:37 -07:00
committed by GitHub
parent fd1bff065a
commit 2e06feafbf
8 changed files with 31 additions and 29 deletions

View File

@@ -1246,6 +1246,7 @@ class Agent(BaseAgent):
message_manager_size = self.message_manager.size(actor=self.user, agent_id=self.agent_state.id)
external_memory_summary = compile_memory_metadata_block(
memory_edit_timestamp=get_utc_time(),
timezone=self.agent_state.timezone,
previous_message_count=self.message_manager.size(actor=self.user, agent_id=self.agent_state.id),
archival_memory_size=self.agent_manager.passage_size(actor=self.user, agent_id=self.agent_state.id),
)

View File

@@ -120,6 +120,7 @@ class BaseAgent(ABC):
system_prompt=agent_state.system,
in_context_memory=agent_state.memory,
in_context_memory_last_edit=memory_edit_timestamp,
timezone=agent_state.timezone,
previous_message_count=num_messages - len(in_context_messages),
archival_memory_size=num_archival_memories,
tool_rules_solver=tool_rules_solver,

View File

@@ -150,6 +150,7 @@ class VoiceAgent(BaseAgent):
system_prompt=agent_state.system,
in_context_memory=agent_state.memory,
in_context_memory_last_edit=memory_edit_timestamp,
timezone=agent_state.timezone,
previous_message_count=self.num_messages,
archival_memory_size=self.num_archival_memories,
)

View File

@@ -6,6 +6,7 @@ LETTA_DIR = os.path.join(os.path.expanduser("~"), ".letta")
LETTA_TOOL_EXECUTION_DIR = os.path.join(LETTA_DIR, "tool_execution_dir")
LETTA_MODEL_ENDPOINT = "https://inference.letta.com"
DEFAULT_TIMEZONE = "UTC"
ADMIN_PREFIX = "/v1/admin"
API_PREFIX = "/v1"

View File

@@ -2,11 +2,12 @@ import re
import time
from datetime import datetime, timedelta
from datetime import timezone as dt_timezone
from time import strftime
from typing import Callable
import pytz
from letta.constants import DEFAULT_TIMEZONE
def parse_formatted_time(formatted_time):
# parse times returned by letta.utils.get_formatted_time()
@@ -18,33 +19,22 @@ def datetime_to_timestamp(dt):
return int(dt.timestamp())
def get_local_time_military():
# Get the current time in UTC
def get_local_time_fast(timezone):
# Get current UTC time and convert to the specified timezone
if not timezone:
return datetime.now().strftime("%Y-%m-%d %I:%M:%S %p %Z%z")
current_time_utc = datetime.now(pytz.utc)
# Convert to San Francisco's time zone (PST/PDT)
sf_time_zone = pytz.timezone("America/Los_Angeles")
local_time = current_time_utc.astimezone(sf_time_zone)
# You may format it as you desire
formatted_time = local_time.strftime("%Y-%m-%d %H:%M:%S %Z%z")
local_time = current_time_utc.astimezone(pytz.timezone(timezone))
formatted_time = local_time.strftime("%Y-%m-%d %I:%M:%S %p %Z%z")
return formatted_time
def get_local_time_fast():
formatted_time = strftime("%Y-%m-%d %I:%M:%S %p %Z%z")
return formatted_time
def get_local_time_timezone(timezone="America/Los_Angeles"):
def get_local_time_timezone(timezone=DEFAULT_TIMEZONE):
# Get the current time in UTC
current_time_utc = datetime.now(pytz.utc)
# Convert to San Francisco's time zone (PST/PDT)
sf_time_zone = pytz.timezone(timezone)
local_time = current_time_utc.astimezone(sf_time_zone)
local_time = current_time_utc.astimezone(pytz.timezone(timezone))
# You may format it as you desire, including AM/PM
formatted_time = local_time.strftime("%Y-%m-%d %I:%M:%S %p %Z%z")
@@ -52,7 +42,7 @@ def get_local_time_timezone(timezone="America/Los_Angeles"):
return formatted_time
def get_local_time(timezone=None):
def get_local_time(timezone=DEFAULT_TIMEZONE):
if timezone is not None:
time_str = get_local_time_timezone(timezone)
else:
@@ -89,8 +79,11 @@ def timestamp_to_datetime(timestamp_seconds: int) -> datetime:
return datetime.fromtimestamp(timestamp_seconds, tz=dt_timezone.utc)
def format_datetime(dt):
return dt.strftime("%Y-%m-%d %I:%M:%S %p %Z%z")
def format_datetime(dt, timezone):
if not timezone:
# use local timezone
return dt.strftime("%Y-%m-%d %I:%M:%S %p %Z%z")
return dt.astimezone(pytz.timezone(timezone)).strftime("%Y-%m-%d %I:%M:%S %p %Z%z")
def validate_date_format(date_str):

View File

@@ -190,7 +190,6 @@ class Agent(SqlalchemyBase, OrganizationMixin, AsyncAttrs):
"response_format": self.response_format,
"last_run_completion": self.last_run_completion,
"last_run_duration_ms": self.last_run_duration_ms,
"timezone": self.timezone,
# optional field defaults
"tags": [],
"tools": [],
@@ -269,7 +268,6 @@ class Agent(SqlalchemyBase, OrganizationMixin, AsyncAttrs):
"response_format": self.response_format,
"last_run_completion": self.last_run_completion,
"last_run_duration_ms": self.last_run_duration_ms,
"timezone": self.timezone,
}
optional_fields = {
"tags": [],

View File

@@ -15,6 +15,7 @@ from letta.constants import (
BASE_TOOLS,
BASE_VOICE_SLEEPTIME_CHAT_TOOLS,
BASE_VOICE_SLEEPTIME_TOOLS,
DEFAULT_TIMEZONE,
FILES_TOOLS,
MULTI_AGENT_TOOLS,
)
@@ -481,7 +482,7 @@ class AgentManager:
response_format=agent_create.response_format,
created_by_id=actor.id,
last_updated_by_id=actor.id,
timezone=agent_create.timezone,
timezone=agent_create.timezone if agent_create.timezone else DEFAULT_TIMEZONE,
)
if _test_only_force_id:
@@ -1429,6 +1430,7 @@ class AgentManager:
system_prompt=agent_state.system,
in_context_memory=agent_state.memory,
in_context_memory_last_edit=memory_edit_timestamp,
timezone=agent_state.timezone,
previous_message_count=num_messages - len(agent_state.message_ids),
archival_memory_size=num_archival_memories,
)
@@ -1503,6 +1505,7 @@ class AgentManager:
system_prompt=agent_state.system,
in_context_memory=agent_state.memory,
in_context_memory_last_edit=memory_edit_timestamp,
timezone=agent_state.timezone,
previous_message_count=num_messages - len(agent_state.message_ids),
archival_memory_size=num_archival_memories,
tool_rules_solver=tool_rules_solver,

View File

@@ -9,7 +9,7 @@ from letta import system
from letta.constants import IN_CONTEXT_MEMORY_KEYWORD, MAX_EMBEDDING_DIM, STRUCTURED_OUTPUT_MODELS
from letta.embeddings import embedding_model
from letta.helpers import ToolRulesSolver
from letta.helpers.datetime_helpers import get_local_time, get_local_time_fast
from letta.helpers.datetime_helpers import format_datetime, get_local_time, get_local_time_fast
from letta.orm import AgentPassage, SourcePassage, SourcesAgents
from letta.orm.agent import Agent as AgentModel
from letta.orm.agents_tags import AgentsTags
@@ -179,17 +179,18 @@ def derive_system_message(agent_type: AgentType, enable_sleeptime: Optional[bool
# TODO: This code is kind of wonky and deserves a rewrite
def compile_memory_metadata_block(
memory_edit_timestamp: datetime,
timezone: str,
previous_message_count: int = 0,
archival_memory_size: int = 0,
) -> str:
# Put the timestamp in the local timezone (mimicking get_local_time())
timestamp_str = memory_edit_timestamp.astimezone().strftime("%Y-%m-%d %I:%M:%S %p %Z%z").strip()
timestamp_str = format_datetime(memory_edit_timestamp, timezone)
# Create a metadata block of info so the agent knows about the metadata of out-of-context memories
memory_metadata_block = "\n".join(
[
"<memory_metadata>",
f"- The current time is: {get_local_time_fast()}",
f"- The current time is: {get_local_time_fast(timezone)}",
f"- Memory blocks were last modified: {timestamp_str}",
f"- {previous_message_count} previous messages between you and the user are stored in recall memory (use tools to access them)",
f"- {archival_memory_size} total memories you created are stored in archival memory (use tools to access them)",
@@ -224,6 +225,7 @@ def compile_system_message(
system_prompt: str,
in_context_memory: Memory,
in_context_memory_last_edit: datetime, # TODO move this inside of BaseMemory?
timezone: str,
user_defined_variables: Optional[dict] = None,
append_icm_if_missing: bool = True,
template_format: Literal["f-string", "mustache", "jinja2"] = "f-string",
@@ -258,6 +260,7 @@ def compile_system_message(
memory_edit_timestamp=in_context_memory_last_edit,
previous_message_count=previous_message_count,
archival_memory_size=archival_memory_size,
timezone=timezone,
)
full_memory_string = in_context_memory.compile(tool_usage_rules=tool_constraint_block) + "\n\n" + memory_metadata_string
@@ -303,6 +306,7 @@ def initialize_message_sequence(
system_prompt=agent_state.system,
in_context_memory=agent_state.memory,
in_context_memory_last_edit=memory_edit_timestamp,
timezone=agent_state.timezone,
user_defined_variables=None,
append_icm_if_missing=True,
previous_message_count=previous_message_count,