fix: Preserve arrays in metadata + refresh OAuth token before sync

1. process_metadata (vector/utils.py):
   - Lists/arrays now preserved as-is (Pinecone supports native arrays)
   - Only datetime and dict types converted to strings
   - Enables Pinecone queries like: filter: {labels: {$in: ['SENT']}}
   - Fixed iteration bug (was modifying dict while iterating)

2. _sync_user_periodic (gmail_auto_sync.py):
   - Now uses OAuth manager to get/refresh token before sync
   - Prevents 'OAuth token expired' errors during attachment fetching
   - Falls back to stored token if refresh fails
This commit is contained in:
PVBLIC Foundation
2025-11-27 05:49:26 -08:00
parent 5841fd0a63
commit f685e58833
2 changed files with 50 additions and 14 deletions
+36 -10
View File
@@ -13,16 +13,42 @@ def filter_metadata(metadata: dict[str, any]) -> dict[str, any]:
def process_metadata(
metadata: dict[str, any],
) -> dict[str, any]:
for key, value in metadata.items():
# Remove large fields
if key in KEYS_TO_EXCLUDE:
del metadata[key]
"""
Process metadata for vector storage.
# Convert non-serializable fields to strings
if (
isinstance(value, datetime)
or isinstance(value, list)
or isinstance(value, dict)
):
- Removes large excluded fields
- Converts non-JSON-serializable types (datetime, dict) to strings
- Preserves lists/arrays (Pinecone supports array filtering with $in)
"""
keys_to_delete = []
for key, value in metadata.items():
# Mark large fields for deletion
if key in KEYS_TO_EXCLUDE:
keys_to_delete.append(key)
continue
# Convert datetime to ISO string
if isinstance(value, datetime):
metadata[key] = value.isoformat()
# Convert dict to string (nested objects not supported in most vector DBs)
elif isinstance(value, dict):
metadata[key] = str(value)
# KEEP lists as-is - Pinecone supports arrays for $in filtering
# e.g., filter: {"labels": {"$in": ["SENT"]}}
elif isinstance(value, list):
# Ensure list items are serializable (strings, numbers, booleans)
metadata[key] = [
(
str(item)
if not isinstance(item, (str, int, float, bool, type(None)))
else item
)
for item in value
]
# Delete excluded keys (can't modify dict while iterating)
for key in keys_to_delete:
del metadata[key]
return metadata
+14 -4
View File
@@ -1238,10 +1238,20 @@ async def _sync_user_periodic(user_id: str) -> bool:
logger.debug(f"⏭️ No Google OAuth session for user {user_id}")
return False
# Use OAuth token from session
# Note: Token refresh happens automatically on next OAuth login
# If token is expired, Gmail API will fail and we'll retry on next cycle
oauth_token = oauth_session.token
# Get refreshed OAuth token using OAuth manager (auto-refreshes if expired)
# This is critical for long-running syncs where token may expire mid-process
try:
from open_webui.main import app
oauth_token = await app.state.oauth_manager.get_oauth_token(
user_id=user_id,
session_id=oauth_session.id,
)
except Exception as e:
logger.warning(
f"⚠️ Failed to get/refresh OAuth token for user {user_id}: {e}"
)
oauth_token = oauth_session.token # Fallback to stored token
# Validation: Check OAuth token exists and has access_token
if not oauth_token or not oauth_token.get("access_token"):