Skip to content

Commit f247686

Browse files
loongzhaoteknium1
authored andcommitted
feat(yuanbao): cache resolved media resources by resourceId
Add an in-memory resourceId->local-path cache (24h TTL, 256-entry LRU) to MediaResolveMiddleware so the same Yuanbao resource isn't re-downloaded when it's referenced more than once in a session (own attachment, then quoted, then group-observed backfill). Each reference otherwise triggers a fresh token exchange + COS download. The cache verifies the file still exists on disk before returning a hit (cache dir may be swept) and is threaded through all three resolve paths: _resolve_media_urls (rid parsed from placeholder URL), _collect_observed_media, and the DispatchMiddleware quote path. Salvaged from PR NousResearch#30418 by @loongfay; the broader middleware refactor in that PR converged with work already merged on main, so only the net-new download cache is carried over.
1 parent f32b66c commit f247686

1 file changed

Lines changed: 63 additions & 1 deletion

File tree

gateway/platforms/yuanbao.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2230,6 +2230,45 @@ class MediaResolveMiddleware(InboundMiddleware):
22302230

22312231
name = "media-resolve"
22322232

2233+
# --- Resource download cache (keyed by resourceId) ---
2234+
# Avoids redundant downloads of the same resource within the TTL window.
2235+
# The same resourceId can be referenced multiple times in a session (own
2236+
# attachment, then quoted again, then observed in a group backfill); each
2237+
# reference otherwise triggers a fresh token exchange + download.
2238+
_resource_cache: ClassVar[Dict[str, Tuple[str, str, float]]] = {} # rid -> (local_path, mime, ts)
2239+
_RESOURCE_CACHE_TTL_S: ClassVar[int] = 24 * 60 * 60 # 24 hours
2240+
_RESOURCE_CACHE_MAX_SIZE: ClassVar[int] = 256
2241+
2242+
@classmethod
2243+
def _get_cached_resource(cls, resource_id: str) -> Optional[Tuple[str, str]]:
2244+
"""Return cached ``(local_path, mime)`` if still valid and file exists, else None."""
2245+
if not resource_id:
2246+
return None
2247+
entry = cls._resource_cache.get(resource_id)
2248+
if entry is None:
2249+
return None
2250+
local_path, mime, ts = entry
2251+
if time.time() - ts > cls._RESOURCE_CACHE_TTL_S:
2252+
cls._resource_cache.pop(resource_id, None)
2253+
return None
2254+
# Verify the cached file still exists on disk (cache dir may be swept).
2255+
if not os.path.isfile(local_path):
2256+
cls._resource_cache.pop(resource_id, None)
2257+
return None
2258+
return local_path, mime
2259+
2260+
@classmethod
2261+
def _put_cached_resource(cls, resource_id: str, local_path: str, mime: str) -> None:
2262+
"""Store download result in cache. Evicts oldest entries when over capacity."""
2263+
if not resource_id:
2264+
return
2265+
if len(cls._resource_cache) >= cls._RESOURCE_CACHE_MAX_SIZE:
2266+
# Drop the oldest 25% of entries by timestamp.
2267+
sorted_keys = sorted(cls._resource_cache, key=lambda k: cls._resource_cache[k][2])
2268+
for k in sorted_keys[: cls._RESOURCE_CACHE_MAX_SIZE // 4]:
2269+
cls._resource_cache.pop(k, None)
2270+
cls._resource_cache[resource_id] = (local_path, mime, time.time())
2271+
22332272
@staticmethod
22342273
def _guess_image_ext_from_url(url: str) -> str:
22352274
"""Guess image extension from URL path."""
@@ -2327,8 +2366,23 @@ async def _resolve_download_url(adapter, url: str) -> str:
23272366
async def _download_and_cache(
23282367
cls, adapter, *, fetch_url: str, kind: str,
23292368
file_name: Optional[str] = None, log_tag: str = "",
2369+
resource_id: str = "",
23302370
) -> Optional[Tuple[str, str]]:
2331-
"""Download a Yuanbao resource and cache locally. Returns ``(local_path, mime)`` or ``None``."""
2371+
"""Download a Yuanbao resource and cache locally. Returns ``(local_path, mime)`` or ``None``.
2372+
2373+
When *resource_id* is provided, an in-memory cache keyed by resourceId
2374+
is consulted first to skip redundant downloads of the same resource
2375+
within the TTL window.
2376+
"""
2377+
if resource_id:
2378+
hit = cls._get_cached_resource(resource_id)
2379+
if hit is not None:
2380+
logger.debug(
2381+
"[%s] resource cache hit: rid=%s path=%s",
2382+
adapter.name, resource_id, hit[0],
2383+
)
2384+
return hit
2385+
23322386
try:
23332387
file_bytes, content_type = await media_download_url(
23342388
fetch_url, max_size_mb=adapter.MEDIA_MAX_SIZE_MB,
@@ -2353,6 +2407,7 @@ async def _download_and_cache(
23532407
mime = guess_mime_type(f"image{ext}")
23542408
if not mime.startswith("image/"):
23552409
mime = content_type if content_type.startswith("image/") else "image/jpeg"
2410+
cls._put_cached_resource(resource_id, local_path, mime)
23562411
return local_path, mime
23572412

23582413
# kind == "file"
@@ -2368,6 +2423,7 @@ async def _download_and_cache(
23682423
)
23692424
return None
23702425
mime = guess_mime_type(file_name) or content_type or "application/octet-stream"
2426+
cls._put_cached_resource(resource_id, local_path, mime)
23712427
return local_path, mime
23722428

23732429
@classmethod
@@ -2393,6 +2449,9 @@ async def _resolve_media_urls(
23932449
if kind not in _RESOLVABLE_MEDIA_KINDS or not url:
23942450
continue
23952451

2452+
# Extract resourceId from the placeholder URL for cache dedup.
2453+
rid = ExtractContentMiddleware._parse_resource_id(url)
2454+
23962455
try:
23972456
fetch_url = await cls._resolve_download_url(adapter, url)
23982457
except Exception as exc:
@@ -2408,6 +2467,7 @@ async def _resolve_media_urls(
24082467
kind=kind,
24092468
file_name=str(ref.get("name") or "").strip() or None,
24102469
log_tag=f"placeholder_url={url[:80]}",
2470+
resource_id=rid,
24112471
)
24122472
if cached is None:
24132473
continue
@@ -2480,6 +2540,7 @@ async def _collect_observed_media(
24802540
kind=kind,
24812541
file_name=filename or None,
24822542
log_tag=f"rid={rid}",
2543+
resource_id=rid,
24832544
)
24842545
if cached is None:
24852546
continue
@@ -2563,6 +2624,7 @@ async def _dispatch_inbound_event() -> None:
25632624
kind=kind,
25642625
file_name=filename or None,
25652626
log_tag=f"quote rid={rid}",
2627+
resource_id=rid,
25662628
)
25672629
if cached is None:
25682630
continue

0 commit comments

Comments
 (0)