fix(backend): use timezone-aware UTC in memory modules (fix pytest DeprecationWarnings) (#1992)

* fix(backend): use timezone-aware UTC in memory modules

Replace datetime.utcnow() with datetime.now(timezone.utc) and a shared
utc_now_iso_z() helper so persisted ISO timestamps keep the trailing Z
suffix without triggering Python 3.12+ deprecation warnings.

Made-with: Cursor

* refactor(backend): use removesuffix for utc_now_iso_z suffix

Makes the +00:00 -> Z transform explicit for the trailing offset only
(Copilot review on PR #1992).

Made-with: Cursor

* style(backend): satisfy ruff UP017 with datetime.UTC in memory queue

Made-with: Cursor

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
Gao Mingfei 2026-04-08 16:28:00 +08:00 committed by GitHub
parent e5b149068c
commit 29817c3b34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 17 additions and 9 deletions

View File

@ -4,7 +4,7 @@ import logging
import threading import threading
import time import time
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime from datetime import UTC, datetime
from typing import Any from typing import Any
from deerflow.config.memory_config import get_memory_config from deerflow.config.memory_config import get_memory_config
@ -18,7 +18,7 @@ class ConversationContext:
thread_id: str thread_id: str
messages: list[Any] messages: list[Any]
timestamp: datetime = field(default_factory=datetime.utcnow) timestamp: datetime = field(default_factory=lambda: datetime.now(UTC))
agent_name: str | None = None agent_name: str | None = None
correction_detected: bool = False correction_detected: bool = False
reinforcement_detected: bool = False reinforcement_detected: bool = False

View File

@ -4,7 +4,7 @@ import abc
import json import json
import logging import logging
import threading import threading
from datetime import datetime from datetime import UTC, datetime
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
@ -15,11 +15,16 @@ from deerflow.config.paths import get_paths
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def utc_now_iso_z() -> str:
"""Current UTC time as ISO-8601 with ``Z`` suffix (matches prior naive-UTC output)."""
return datetime.now(UTC).isoformat().removesuffix("+00:00") + "Z"
def create_empty_memory() -> dict[str, Any]: def create_empty_memory() -> dict[str, Any]:
"""Create an empty memory structure.""" """Create an empty memory structure."""
return { return {
"version": "1.0", "version": "1.0",
"lastUpdated": datetime.utcnow().isoformat() + "Z", "lastUpdated": utc_now_iso_z(),
"user": { "user": {
"workContext": {"summary": "", "updatedAt": ""}, "workContext": {"summary": "", "updatedAt": ""},
"personalContext": {"summary": "", "updatedAt": ""}, "personalContext": {"summary": "", "updatedAt": ""},
@ -137,7 +142,7 @@ class FileMemoryStorage(MemoryStorage):
try: try:
file_path.parent.mkdir(parents=True, exist_ok=True) file_path.parent.mkdir(parents=True, exist_ok=True)
memory_data["lastUpdated"] = datetime.utcnow().isoformat() + "Z" memory_data["lastUpdated"] = utc_now_iso_z()
temp_path = file_path.with_suffix(".tmp") temp_path = file_path.with_suffix(".tmp")
with open(temp_path, "w", encoding="utf-8") as f: with open(temp_path, "w", encoding="utf-8") as f:

View File

@ -5,14 +5,17 @@ import logging
import math import math
import re import re
import uuid import uuid
from datetime import datetime
from typing import Any from typing import Any
from deerflow.agents.memory.prompt import ( from deerflow.agents.memory.prompt import (
MEMORY_UPDATE_PROMPT, MEMORY_UPDATE_PROMPT,
format_conversation_for_update, format_conversation_for_update,
) )
from deerflow.agents.memory.storage import create_empty_memory, get_memory_storage from deerflow.agents.memory.storage import (
create_empty_memory,
get_memory_storage,
utc_now_iso_z,
)
from deerflow.config.memory_config import get_memory_config from deerflow.config.memory_config import get_memory_config
from deerflow.models import create_chat_model from deerflow.models import create_chat_model
@ -86,7 +89,7 @@ def create_memory_fact(
normalized_category = category.strip() or "context" normalized_category = category.strip() or "context"
validated_confidence = _validate_confidence(confidence) validated_confidence = _validate_confidence(confidence)
now = datetime.utcnow().isoformat() + "Z" now = utc_now_iso_z()
memory_data = get_memory_data(agent_name) memory_data = get_memory_data(agent_name)
updated_memory = dict(memory_data) updated_memory = dict(memory_data)
facts = list(memory_data.get("facts", [])) facts = list(memory_data.get("facts", []))
@ -376,7 +379,7 @@ class MemoryUpdater:
Updated memory data. Updated memory data.
""" """
config = get_memory_config() config = get_memory_config()
now = datetime.utcnow().isoformat() + "Z" now = utc_now_iso_z()
# Update user sections # Update user sections
user_updates = update_data.get("user", {}) user_updates = update_data.get("user", {})