From 526cb912ff46fb0fb8ecf8079a3bcc8f9425e163 Mon Sep 17 00:00:00 2001 From: lmdnipo <18809296239@163.com> Date: Wed, 28 Oct 2026 14:08:51 +0800 Subject: [PATCH 1/3] fix(core): handle .md webfetch URLs --- packages/core/src/tool/plugin/webfetch.ts | 6 +++--- packages/core/test/tool-webfetch.test.ts | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/core/src/tool/plugin/webfetch.ts b/packages/core/src/tool/plugin/webfetch.ts index 3c9cf10926c4..bb2edfbcd319 100644 --- a/packages/core/src/tool/plugin/webfetch.ts +++ b/packages/core/src/tool/plugin/webfetch.ts @@ -50,9 +50,9 @@ const acceptHeader = (format: Format) => { } } -const headers = (format: Format, userAgent: string) => ({ +const headers = (url: string, format: Format, userAgent: string) => ({ "User-Agent": userAgent, - Accept: acceptHeader(format), + Accept: new URL(url).pathname.toLowerCase().endsWith(".md") ? "*/*" : acceptHeader(format), "Accept-Language": "en-US,en;q=0.9", }) @@ -66,7 +66,7 @@ const isCloudflareChallenge = (error: unknown) => { } const request = (url: string, format: Format, userAgent = openCodeUserAgent) => - HttpClientRequest.get(url).pipe(HttpClientRequest.setHeaders(headers(format, userAgent))) + HttpClientRequest.get(url).pipe(HttpClientRequest.setHeaders(headers(url, format, userAgent))) const assertHttpUrl = (url: URL) => { if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("URL must use http:// or https://") diff --git a/packages/core/test/tool-webfetch.test.ts b/packages/core/test/tool-webfetch.test.ts index 1b6cbe85f317..b64acbbf00c9 100644 --- a/packages/core/test/tool-webfetch.test.ts +++ b/packages/core/test/tool-webfetch.test.ts @@ -455,6 +455,20 @@ describe("WebFetchTool registration", () => { }), ) + it.effect("does not negotiate markdown for .md URLs", () => + Effect.gen(function* () { + reset() + const registry = yield* Tool.Service + const url = "https://docs.example.com/page.md?source=llms.txt" + + yield* Effect.forEach(["markdown", "text", "html"] as const, (format) => + executeTool(registry, call({ url, format }, `call-webfetch-${format}`)), + ) + + expect(requests.map((request) => request.headers.accept)).toEqual(["*/*", "*/*", "*/*"]) + }), + ) + it.effect("accepts localhost URLs with the same requested-URL permission check", () => Effect.gen(function* () { reset() From 792af84bbdda60cc7670c511a333d271ad811a6d Mon Sep 17 00:00:00 2001 From: lmdnipo <18809296239@163.com> Date: Thu, 29 Oct 2026 12:26:43 +0800 Subject: [PATCH 2/3] fix(core): handle .markdown webfetch URLs --- packages/core/src/tool/plugin/webfetch.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/core/src/tool/plugin/webfetch.ts b/packages/core/src/tool/plugin/webfetch.ts index bb2edfbcd319..5f59790721d0 100644 --- a/packages/core/src/tool/plugin/webfetch.ts +++ b/packages/core/src/tool/plugin/webfetch.ts @@ -50,11 +50,16 @@ const acceptHeader = (format: Format) => { } } -const headers = (url: string, format: Format, userAgent: string) => ({ - "User-Agent": userAgent, - Accept: new URL(url).pathname.toLowerCase().endsWith(".md") ? "*/*" : acceptHeader(format), - "Accept-Language": "en-US,en;q=0.9", -}) +const headers = (url: string, format: Format, userAgent: string) => { + const pathname = new URL(url).pathname.toLowerCase() + const isMarkdownPath = pathname.endsWith(".md") || pathname.endsWith(".markdown") + + return { + "User-Agent": userAgent, + Accept: isMarkdownPath ? "*/*" : acceptHeader(format), + "Accept-Language": "en-US,en;q=0.9", + } +} const openCodeUserAgent = "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; OpenCode-User/1.0; +https://opencode.ai" From db48b449d662dbfb6ad9dbf8c0d4f5bb0a737392 Mon Sep 17 00:00:00 2001 From: lmdnipo <18809296239@163.com> Date: Thu, 29 Oct 2026 12:34:49 +0800 Subject: [PATCH 3/3] test(core): cover .markdown webfetch URLs --- packages/core/test/tool-webfetch.test.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/core/test/tool-webfetch.test.ts b/packages/core/test/tool-webfetch.test.ts index b64acbbf00c9..b1cab6c80cbd 100644 --- a/packages/core/test/tool-webfetch.test.ts +++ b/packages/core/test/tool-webfetch.test.ts @@ -455,17 +455,24 @@ describe("WebFetchTool registration", () => { }), ) - it.effect("does not negotiate markdown for .md URLs", () => + it.effect("does not negotiate markdown for .md and .markdown URLs", () => Effect.gen(function* () { reset() const registry = yield* Tool.Service - const url = "https://docs.example.com/page.md?source=llms.txt" - - yield* Effect.forEach(["markdown", "text", "html"] as const, (format) => - executeTool(registry, call({ url, format }, `call-webfetch-${format}`)), + const urls = [ + "https://docs.example.com/page.md?source=llms.txt", + "https://docs.example.com/page.markdown?source=llms.txt", + ] + + yield* Effect.forEach(urls, (url) => + Effect.forEach(["markdown", "text", "html"] as const, (format) => + executeTool(registry, call({ url, format }, `call-webfetch-${format}`)), + ), ) - expect(requests.map((request) => request.headers.accept)).toEqual(["*/*", "*/*", "*/*"]) + expect(requests.map((request) => request.headers.accept)).toEqual( + Array.from({ length: urls.length * 3 }, () => "*/*"), + ) }), )