|
|
@@ -1,4 +1,5 @@
|
|
|
import { afterEach, describe, expect, mock, test } from 'bun:test';
|
|
|
+import { CACHE } from './cache';
|
|
|
import { createWebfetchTool } from './tool';
|
|
|
|
|
|
function createExecutionContext() {
|
|
|
@@ -15,6 +16,7 @@ describe('smartfetch/tool', () => {
|
|
|
|
|
|
afterEach(() => {
|
|
|
globalThis.fetch = originalFetch;
|
|
|
+ CACHE.clear();
|
|
|
mock.restore();
|
|
|
});
|
|
|
|
|
|
@@ -57,4 +59,65 @@ describe('smartfetch/tool', () => {
|
|
|
expect(ctx.ask).toHaveBeenCalledTimes(1);
|
|
|
expect(ctx.metadata).not.toHaveBeenCalled();
|
|
|
});
|
|
|
+
|
|
|
+ test('same document with different fragments issues a single request', async () => {
|
|
|
+ CACHE.clear();
|
|
|
+
|
|
|
+ const fetchMock = mock(async (input: string | URL | Request) => {
|
|
|
+ const url = typeof input === 'string' ? input : input.toString();
|
|
|
+
|
|
|
+ if (url === 'https://example.com/docs') {
|
|
|
+ return new Response('document body', {
|
|
|
+ status: 200,
|
|
|
+ headers: { 'content-type': 'text/plain' },
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ throw new Error(`Unexpected fetch URL: ${url}`);
|
|
|
+ });
|
|
|
+ globalThis.fetch = fetchMock as unknown as typeof fetch;
|
|
|
+
|
|
|
+ const webfetch = createWebfetchTool({ client: {} } as any);
|
|
|
+
|
|
|
+ const firstCtx = createExecutionContext();
|
|
|
+ const firstResult = await webfetch.execute(
|
|
|
+ {
|
|
|
+ url: 'https://example.com/docs#sec1',
|
|
|
+ format: 'markdown',
|
|
|
+ extract_main: true,
|
|
|
+ prefer_llms_txt: 'auto',
|
|
|
+ include_metadata: true,
|
|
|
+ save_binary: false,
|
|
|
+ },
|
|
|
+ firstCtx,
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
|
+ expect(firstResult).toContain(
|
|
|
+ 'requested_url: "https://example.com/docs#sec1"',
|
|
|
+ );
|
|
|
+ expect(firstResult).toContain('cache_hit: false');
|
|
|
+
|
|
|
+ const secondCtx = createExecutionContext();
|
|
|
+ const secondResult = await webfetch.execute(
|
|
|
+ {
|
|
|
+ url: 'https://example.com/docs#sec2',
|
|
|
+ format: 'markdown',
|
|
|
+ extract_main: true,
|
|
|
+ prefer_llms_txt: 'auto',
|
|
|
+ include_metadata: true,
|
|
|
+ save_binary: false,
|
|
|
+ },
|
|
|
+ secondCtx,
|
|
|
+ );
|
|
|
+
|
|
|
+ // The fragment-stripped cache key collides with the first request, so
|
|
|
+ // the second fetch is served from cache without hitting the network,
|
|
|
+ // and the reported requested_url stays the URL of the current request.
|
|
|
+ expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
|
+ expect(secondResult).toContain('cache_hit: true');
|
|
|
+ expect(secondResult).toContain(
|
|
|
+ 'requested_url: "https://example.com/docs#sec2"',
|
|
|
+ );
|
|
|
+ });
|
|
|
});
|