MCPcopy Index your code
hub / github.com/promptfoo/promptfoo / fetchWithCache

Function fetchWithCache

src/cache.ts:749–832  ·  view source on GitHub ↗
(
  url: RequestInfo,
  options: RequestInit = {},
  timeout: number = getRequestTimeoutMs(),
  format: 'json' | 'text' = 'json',
  bustOrOptions: boolean | CacheOptions | undefined = false,
  maxRetries?: number,
)

Source from the content-addressed store, hash-verified

747 * @see enableCache / disableCache for cache control
748 */
749export async function fetchWithCache<T = unknown>(
750 url: RequestInfo,
751 options: RequestInit = {},
752 timeout: number = getRequestTimeoutMs(),
753 format: 'json' | 'text' = 'json',
754 bustOrOptions: boolean | CacheOptions | undefined = false,
755 maxRetries?: number,
756): Promise<FetchWithCacheResult<T>> {
757 const cacheOptions: CacheOptions =
758 typeof bustOrOptions === 'boolean' ? { bust: bustOrOptions } : (bustOrOptions ?? {});
759 const { bust = false, repeatIndex } = cacheOptions;
760
761 // Only retry body-read for idempotent methods to avoid double-submitting
762 // POST/PATCH requests (the server already processed the request once
763 // headers arrived; only the response body stream failed).
764 const method = (options.method ?? (url instanceof Request ? url.method : 'GET')).toUpperCase();
765 const isIdempotent = ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE'].includes(method);
766
767 const cacheEnabled = getEffectiveCacheEnabled();
768 const cacheKey =
769 cacheEnabled && !bust ? getFetchCacheKey(url, options, method, format, repeatIndex) : null;
770
771 if (!cacheEnabled || bust || cacheKey == null) {
772 const { respText, resp, fetchLatencyMs } = await fetchAndReadBody(
773 url,
774 options,
775 timeout,
776 maxRetries,
777 isIdempotent,
778 );
779 try {
780 return {
781 cached: false,
782 data: format === 'json' ? JSON.parse(respText) : respText,
783 status: resp.status,
784 statusText: resp.statusText,
785 headers: Object.fromEntries(resp.headers.entries()),
786 latencyMs: fetchLatencyMs,
787 deleteFromCache: async () => {
788 // No-op when cache is disabled
789 },
790 };
791 } catch (err) {
792 throw new Error(
793 `Error parsing response from ${url}: ${
794 (err as Error).message
795 }. HTTP ${resp.status} ${resp.statusText}. Received text: ${respText}`,
796 );
797 }
798 }
799
800 const cache = getCacheInstance();
801
802 const cachedResponse = await cache.get<SerializedFetchResponse>(cacheKey);
803 if (cachedResponse != null) {
804 logger.debug(`Returning cached response for ${url}: ${cachedResponse}`);
805 return deserializeFetchResponse<T>(cachedResponse, true, cache, cacheKey);
806 }

Callers 15

cache.test.tsFile · 0.90
makeRequestFunction · 0.90
makeAdaptiveRequestFunction · 0.90
doRemoteGradingFunction · 0.90
fetchModelSpecsFunction · 0.90
performTokenRefreshMethod · 0.90
callApiInternalMethod · 0.90
callApiWithRawRequestMethod · 0.90
callApiInternalMethod · 0.90
callEmbeddingApiMethod · 0.90

Calls 12

getRequestTimeoutMsFunction · 0.90
getEffectiveCacheEnabledFunction · 0.85
getFetchCacheKeyFunction · 0.85
fetchAndReadBodyFunction · 0.85
getCacheInstanceFunction · 0.85
deserializeFetchResponseFunction · 0.85
getInflightFetchCacheKeyFunction · 0.85
prepareFetchResponseFunction · 0.85
parseMethod · 0.80
deleteMethod · 0.65
getMethod · 0.45
setMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…