diff --git a/hindsight-api-slim/hindsight_api/engine/retain/fact_storage.py b/hindsight-api-slim/hindsight_api/engine/retain/fact_storage.py index c0ac9b12..412ecbfb 100644 --- a/hindsight-api-slim/hindsight_api/engine/retain/fact_storage.py +++ b/hindsight-api-slim/hindsight_api/engine/retain/fact_storage.py @@ -81,9 +81,15 @@ async def insert_facts_batch( if fact.entities: signal_parts.extend(e.name for e in fact.entities) if fact.occurred_start: - signal_parts.append(fact.occurred_start.strftime("%B %-d %Y")) + try: + signal_parts.append(fact.occurred_start.strftime("%B %d %Y").lstrip("0").replace(" 0", " ")) + except (ValueError, AttributeError): + pass if fact.occurred_end and fact.occurred_end != fact.occurred_start: - signal_parts.append(fact.occurred_end.strftime("%B %-d %Y")) + try: + signal_parts.append(fact.occurred_end.strftime("%B %d %Y").lstrip("0").replace(" 0", " ")) + except (ValueError, AttributeError): + pass text_signals_list.append(" ".join(signal_parts) if signal_parts else None) # Batch insert all facts diff --git a/hindsight-api-slim/hindsight_api/main.py b/hindsight-api-slim/hindsight_api/main.py index 2cd23ae0..b8349fe3 100644 --- a/hindsight-api-slim/hindsight_api/main.py +++ b/hindsight-api-slim/hindsight_api/main.py @@ -211,15 +211,24 @@ def main(): # Prepare uvicorn config # When using workers or reload, we must use import string so each worker can import the app use_import_string = args.workers > 1 or args.reload - # Check for uvloop availability - try: - import uvloop # noqa: F401 - - loop_impl = "uvloop" - print("uvloop available, will use for event loop") - except ImportError: - loop_impl = "asyncio" - print("uvloop not installed, using default asyncio event loop") + # Check for uvloop/winloop availability + import sys + loop_impl = "asyncio" + if sys.platform == "win32": + try: + import winloop + winloop.install() # Patches asyncio globally — uvicorn uses "asyncio" but gets winloop + loop_impl = "asyncio" # Tell uvicorn "asyncio" — it's now winloop underneath + print("winloop installed as asyncio event loop policy (Windows uvloop port)") + except ImportError: + print("winloop not installed, using default asyncio event loop") + else: + try: + import uvloop # noqa: F401 + loop_impl = "uvloop" + print("uvloop available, will use for event loop") + except ImportError: + print("uvloop not installed, using default asyncio event loop") uvicorn_config = { "app": "hindsight_api.server:app" if use_import_string else app, diff --git a/hindsight-api-slim/hindsight_api/metrics.py b/hindsight-api-slim/hindsight_api/metrics.py index 5fd5c3d5..8fddc281 100644 --- a/hindsight-api-slim/hindsight_api/metrics.py +++ b/hindsight-api-slim/hindsight_api/metrics.py @@ -13,7 +13,10 @@ This module provides metrics for: import logging import os -import resource +try: + import resource +except ImportError: + resource = None # Windows doesn't have resource module import threading import time from contextlib import contextmanager @@ -455,6 +458,8 @@ class MetricsCollector(MetricsCollectorBase): def _setup_process_metrics(self): """Set up observable gauges for process metrics.""" + if resource is None: + return # Skip process metrics on Windows def get_cpu_times(_options): """Get process CPU times.""" diff --git a/hindsight-api-slim/pyproject.toml b/hindsight-api-slim/pyproject.toml index 767e6d24..916c496f 100644 --- a/hindsight-api-slim/pyproject.toml +++ b/hindsight-api-slim/pyproject.toml @@ -43,7 +43,8 @@ dependencies = [ "litellm>=1.0.0,<=1.82.6", # 1.82.7+ contains a supply chain attack (malicious .pth credential stealer) "markitdown[pdf,docx,pptx,xlsx,xls]>=0.1.4", # File to markdown conversion "obstore>=0.4.0", # S3/GCS/Azure object storage client (Rust-backed) - "uvloop>=0.22.1", + "winloop>=0.1.0; sys_platform == 'win32'", + "uvloop>=0.22.1; sys_platform != 'win32'", # Transitive dependency security fixes "pyasn1>=0.6.3", # DoS vulnerability fix "urllib3>=2.6.3", # Decompression-bomb safeguards bypass fix