diff --git a/gateway/platforms/yuanbao.py b/gateway/platforms/yuanbao.py index 4657afd5219..7145ec57877 100644 --- a/gateway/platforms/yuanbao.py +++ b/gateway/platforms/yuanbao.py @@ -2829,6 +2829,8 @@ class MediaResolveMiddleware(InboundMiddleware): for the same order-preserving / exception-isolated contract. """ # Pre-filter resolvable refs, preserving input order. + media_urls: List[str] = [] + media_types: List[str] = [] active: List[Tuple[str, str, str, str]] = [] for ref in media_refs: kind = str(ref.get("kind") or "").strip().lower() @@ -2837,25 +2839,18 @@ class MediaResolveMiddleware(InboundMiddleware): if kind not in _RESOLVABLE_MEDIA_KINDS or not url: continue rid = ExtractContentMiddleware._parse_resource_id(url) - active.append((kind, url, filename, rid)) + if rid and cls._append_cached_resource(adapter, rid, media_urls, media_types): + continue + active.append((kind, url, filename, rid or "")) if not active: - return [], [] + return media_urls, media_types semaphore = asyncio.Semaphore(adapter.media_resolve_concurrency) async def _resolve_one( kind: str, url: str, filename: str, rid: str, ) -> Optional[Tuple[str, str]]: - # Cache dedup first — avoids the RPC + download entirely on a hit. - if rid: - hit = cls._get_cached_resource(rid) - if hit is not None: - logger.debug( - "[%s] resource cache hit: rid=%s path=%s", - adapter.name, rid, hit[0], - ) - return hit async with semaphore: try: fetch_url = await cls._resolve_download_url(adapter, url) @@ -2882,8 +2877,6 @@ class MediaResolveMiddleware(InboundMiddleware): ) _elapsed_ms = int((time.monotonic() - _t0) * 1000) - media_urls: List[str] = [] - media_types: List[str] = [] _failed = 0 for (kind, url, _filename, _rid), result in zip(active, results): if isinstance(result, BaseException): @@ -2928,25 +2921,22 @@ class MediaResolveMiddleware(InboundMiddleware): sequentially. Output order matches input; per-rid failures are isolated. """ # Pre-filter resolvable kinds, preserving input order. - active: List[Tuple[str, str, str]] = [ - (rid, kind, filename) - for rid, kind, filename in refs - if kind in _RESOLVABLE_MEDIA_KINDS - ] + # Cache-hit refs are served immediately and excluded from the gather. + media_paths: List[str] = [] + mimes: List[str] = [] + active: List[Tuple[str, str, str]] = [] + for rid, kind, filename in refs: + if kind not in _RESOLVABLE_MEDIA_KINDS: + continue + if cls._append_cached_resource(adapter, rid, media_paths, mimes): + continue + active.append((rid, kind, filename)) if not active: - return [], [] + return media_paths, mimes semaphore = asyncio.Semaphore(adapter.media_resolve_concurrency) async def _resolve_one(rid: str, kind: str, filename: str) -> Optional[Tuple[str, str]]: - # Cache dedup first — avoids the RPC + download entirely on a hit. - hit = cls._get_cached_resource(rid) - if hit is not None: - logger.debug( - "[%s] resource cache hit: rid=%s path=%s", - adapter.name, rid, hit[0], - ) - return hit async with semaphore: try: fresh_url = await cls._fetch_resource_url(adapter, rid) @@ -2973,10 +2963,8 @@ class MediaResolveMiddleware(InboundMiddleware): ) _elapsed_ms = int((time.monotonic() - _t0) * 1000) - media_paths: List[str] = [] - mimes: List[str] = [] _failed = 0 - for (rid, kind, _filename), result in zip(active, results): + for (rid, kind, filename), result in zip(active, results): if isinstance(result, BaseException): logger.warning( "[%s] %s resolve crashed: rid=%s kind=%s err=%s",