mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-27 22:10:11 -04:00
refactor(core): simplify WebFetch error narrowing (#45582)
Use the typed HTTP error reason instead of manual object probing and an unchecked response cast. Preserve the single challenge-only retry and cover ordinary 403 failures without retry.
This commit is contained in:
@@ -3,7 +3,7 @@ export * as WebFetchTool from "./webfetch.js"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { Duration, Effect, Schema } from "effect"
|
||||
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
import { HttpClient, type HttpClientError, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
import { Parser } from "htmlparser2"
|
||||
import { Permission } from "../../permission.js"
|
||||
import { convertHTMLToMarkdown, MAX_MARKDOWN_BYTES } from "../html-markdown.js"
|
||||
@@ -58,18 +58,9 @@ const headers = (format: Format, userAgent: string) => ({
|
||||
const openCodeUserAgent =
|
||||
"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; OpenCode-User/1.0; +https://opencode.ai"
|
||||
|
||||
const isCloudflareChallenge = (error: unknown) => {
|
||||
if (!error || typeof error !== "object" || !("reason" in error)) return false
|
||||
const reason = error.reason
|
||||
if (
|
||||
!reason ||
|
||||
typeof reason !== "object" ||
|
||||
!("_tag" in reason) ||
|
||||
reason._tag !== "StatusCodeError" ||
|
||||
!("response" in reason)
|
||||
)
|
||||
return false
|
||||
const response = reason.response as HttpClientResponse.HttpClientResponse
|
||||
const isCloudflareChallenge = (error: HttpClientError.HttpClientError) => {
|
||||
if (error.reason._tag !== "StatusCodeError") return false
|
||||
const response = error.reason.response
|
||||
return response.status === 403 && response.headers["cf-mitigated"] === "challenge"
|
||||
}
|
||||
|
||||
|
||||
@@ -573,6 +573,22 @@ describe("WebFetchTool registration", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("does not retry ordinary 403 responses", () =>
|
||||
Effect.gen(function* () {
|
||||
reset()
|
||||
respond = () => Effect.succeed(new Response("forbidden", { status: 403 }))
|
||||
const registry = yield* Tool.Service
|
||||
const url = "https://example.com/forbidden"
|
||||
|
||||
expect(yield* executeTool(registry, call({ url, format: "text" }))).toEqual({
|
||||
status: "error",
|
||||
error: { type: "unknown", message: `StatusCode: non 2xx status code (403 GET ${url})` },
|
||||
})
|
||||
expect(requests).toHaveLength(1)
|
||||
expect(requests[0]?.headers["user-agent"]).toBe(webFetchUserAgent)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("times out stalled requests", () =>
|
||||
Effect.gen(function* () {
|
||||
reset()
|
||||
|
||||
Reference in New Issue
Block a user