date fx
This commit is contained in:
@@ -28,21 +28,41 @@ depends_on: str | Sequence[str] | None = None
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# Use IF NOT EXISTS — this is a catch-up migration for columns that
|
||||
# may already exist (inserted by out-of-band schema changes).
|
||||
conn = op.get_bind()
|
||||
|
||||
# Add is_multimodal to llm_providers (from 9f8e7d6c5b4a)
|
||||
op.add_column("llm_providers",
|
||||
sa.Column("is_multimodal", sa.Boolean(), nullable=False, server_default="false")
|
||||
)
|
||||
op.alter_column("llm_providers", "is_multimodal", server_default=None)
|
||||
if not _column_exists(conn, "llm_providers", "is_multimodal"):
|
||||
op.add_column("llm_providers",
|
||||
sa.Column("is_multimodal", sa.Boolean(), nullable=False, server_default="false")
|
||||
)
|
||||
op.alter_column("llm_providers", "is_multimodal", server_default=None)
|
||||
|
||||
# Add provider_id to validation_policies (from a7b1c2d3e4f5)
|
||||
op.add_column("validation_policies",
|
||||
sa.Column("provider_id", sa.String(), nullable=True)
|
||||
)
|
||||
if not _column_exists(conn, "validation_policies", "provider_id"):
|
||||
op.add_column("validation_policies",
|
||||
sa.Column("provider_id", sa.String(), nullable=True)
|
||||
)
|
||||
|
||||
# Add policy_id to llm_validation_results (from b1c2d3e4f5a6)
|
||||
op.add_column("llm_validation_results",
|
||||
sa.Column("policy_id", sa.String(), nullable=True, index=True)
|
||||
if not _column_exists(conn, "llm_validation_results", "policy_id"):
|
||||
op.add_column("llm_validation_results",
|
||||
sa.Column("policy_id", sa.String(), nullable=True, index=True)
|
||||
)
|
||||
|
||||
|
||||
def _column_exists(conn, table: str, column: str) -> bool:
|
||||
"""Check if a column exists in the given table."""
|
||||
from sqlalchemy import text
|
||||
result = conn.execute(
|
||||
text(
|
||||
"SELECT 1 FROM information_schema.columns "
|
||||
"WHERE table_name = :table AND column_name = :column"
|
||||
),
|
||||
{"table": table, "column": column},
|
||||
)
|
||||
return result.scalar() is not None
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from fastapi import Depends, HTTPException, Query
|
||||
@@ -69,7 +69,7 @@ async def list_conversations(
|
||||
conv_id = row.conversation_id
|
||||
if not conv_id:
|
||||
continue
|
||||
created_at = row.created_at or datetime.now(UTC)
|
||||
created_at = row.created_at or datetime.now()
|
||||
if conv_id not in summary:
|
||||
summary[conv_id] = {
|
||||
"conversation_id": conv_id,
|
||||
|
||||
@@ -301,7 +301,7 @@ def _resolve_or_create_conversation(
|
||||
# @PRE db session is available and user_id references current actor scope.
|
||||
# @POST Messages older than ASSISTANT_MESSAGE_TTL_DAYS are removed from persistence and memory mirrors.
|
||||
def _cleanup_history_ttl(db: Session, user_id: str):
|
||||
cutoff = datetime.now(UTC) - timedelta(days=ASSISTANT_MESSAGE_TTL_DAYS)
|
||||
cutoff = datetime.now() - timedelta(days=ASSISTANT_MESSAGE_TTL_DAYS)
|
||||
try:
|
||||
query = db.query(AssistantMessageRecord).filter(
|
||||
AssistantMessageRecord.user_id == user_id,
|
||||
@@ -323,8 +323,11 @@ def _cleanup_history_ttl(db: Session, user_id: str):
|
||||
kept = []
|
||||
for item in items:
|
||||
created_at = item.get("created_at")
|
||||
if isinstance(created_at, datetime) and created_at < cutoff:
|
||||
continue
|
||||
if isinstance(created_at, datetime):
|
||||
# DB stores naive datetimes; in-memory items may be aware (from datetime.now(UTC))
|
||||
ref = created_at.replace(tzinfo=None) if created_at.tzinfo else created_at
|
||||
if ref < cutoff:
|
||||
continue
|
||||
kept.append(item)
|
||||
if kept:
|
||||
CONVERSATIONS[key] = kept
|
||||
@@ -344,8 +347,10 @@ def _cleanup_history_ttl(db: Session, user_id: str):
|
||||
def _is_conversation_archived(updated_at: datetime | None) -> bool:
|
||||
if not updated_at:
|
||||
return False
|
||||
cutoff = datetime.now(UTC) - timedelta(days=ASSISTANT_ARCHIVE_AFTER_DAYS)
|
||||
return updated_at < cutoff
|
||||
cutoff = datetime.now() - timedelta(days=ASSISTANT_ARCHIVE_AFTER_DAYS)
|
||||
# Ensure both operands are naive (DB stores naive datetimes)
|
||||
ref = updated_at.replace(tzinfo=None) if updated_at.tzinfo else updated_at
|
||||
return ref < cutoff
|
||||
|
||||
|
||||
# #endregion _is_conversation_archived
|
||||
|
||||
@@ -1122,7 +1122,8 @@ class LLMClient:
|
||||
return model_ids
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"[LLMClient.fetch_models] Failed to fetch models: {e}",
|
||||
f"[LLMClient.fetch_models] Failed to fetch models.\n"
|
||||
f"{self._format_connection_error(e)}",
|
||||
)
|
||||
raise
|
||||
# endregion LLMClient.fetch_models
|
||||
|
||||
Reference in New Issue
Block a user