mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 16:25:51 +00:00
fix: review — Brave API key + webFetchHttpTimeoutMs 联动 + Tavily URL 推导
- braveAdapter: 读取 settings.braveApiKey (优先于环境变量) - webFetch utils: getFetchTimeoutMs() 统一读取 settings.webFetchHttpTimeoutMs,HTTP/Tavily 两条路径均生效 - tavilyAdapter: 自定义端点自动追加 /search 路径(与 fetchContentWithTavily 一致) Co-Authored-By: deepseek-v4-pro <deepseek-ai@claude-code-best.win>
This commit is contained in:
@@ -117,10 +117,19 @@ const MAX_HTTP_CONTENT_LENGTH = 10 * 1024 * 1024
|
|||||||
|
|
||||||
// Timeout for the main HTTP fetch request (60 seconds).
|
// Timeout for the main HTTP fetch request (60 seconds).
|
||||||
// Prevents hanging indefinitely on slow/unresponsive servers.
|
// Prevents hanging indefinitely on slow/unresponsive servers.
|
||||||
const FETCH_TIMEOUT_MS = 60_000
|
// Overridable via settings.webFetchHttpTimeoutMs (set in /web-tools panel).
|
||||||
|
const DEFAULT_FETCH_TIMEOUT_MS = 60_000
|
||||||
|
|
||||||
|
function getFetchTimeoutMs(): number {
|
||||||
|
const settings = getSettings_DEPRECATED() as Record<string, unknown> & {
|
||||||
|
webFetchHttpTimeoutMs?: number
|
||||||
|
}
|
||||||
|
return settings.webFetchHttpTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS
|
||||||
|
}
|
||||||
|
|
||||||
// Cap same-host redirect hops. Without this a malicious server can return
|
// Cap same-host redirect hops. Without this a malicious server can return
|
||||||
// a redirect loop (/a → /b → /a …) and the per-request FETCH_TIMEOUT_MS
|
// a redirect loop (/a → /b → /a …) and the per-request timeout
|
||||||
|
// (controlled by settings.webFetchHttpTimeoutMs)
|
||||||
// resets on every hop, hanging the tool until user interrupt. 10 matches
|
// resets on every hop, hanging the tool until user interrupt. 10 matches
|
||||||
// common client defaults (axios=5, follow-redirects=21, Chrome=20).
|
// common client defaults (axios=5, follow-redirects=21, Chrome=20).
|
||||||
const MAX_REDIRECTS = 10
|
const MAX_REDIRECTS = 10
|
||||||
@@ -238,7 +247,7 @@ export async function getWithPermittedRedirects(
|
|||||||
try {
|
try {
|
||||||
return await axios.get(url, {
|
return await axios.get(url, {
|
||||||
signal,
|
signal,
|
||||||
timeout: FETCH_TIMEOUT_MS,
|
timeout: getFetchTimeoutMs(),
|
||||||
maxRedirects: 0,
|
maxRedirects: 0,
|
||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
maxContentLength: MAX_HTTP_CONTENT_LENGTH,
|
maxContentLength: MAX_HTTP_CONTENT_LENGTH,
|
||||||
@@ -488,7 +497,7 @@ export async function fetchContentWithTavily(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
signal: abortSignal,
|
signal: abortSignal,
|
||||||
timeout: FETCH_TIMEOUT_MS,
|
timeout: getFetchTimeoutMs(),
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { AbortError } from 'src/utils/errors.js'
|
import { AbortError } from 'src/utils/errors.js'
|
||||||
|
import { getSettings_DEPRECATED } from 'src/utils/settings/settings.js'
|
||||||
import type { SearchResult, SearchOptions, WebSearchAdapter } from './types.js'
|
import type { SearchResult, SearchOptions, WebSearchAdapter } from './types.js'
|
||||||
|
|
||||||
const FETCH_TIMEOUT_MS = 30_000
|
const FETCH_TIMEOUT_MS = 30_000
|
||||||
@@ -156,6 +157,14 @@ function normalizeSnippet(snippets: string[] | undefined): string | undefined {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getBraveApiKey(): string {
|
function getBraveApiKey(): string {
|
||||||
|
// Priority: settings.braveApiKey (from /web-tools panel) > environment variable
|
||||||
|
const settings = getSettings_DEPRECATED() as Record<string, unknown> & {
|
||||||
|
braveApiKey?: string
|
||||||
|
}
|
||||||
|
if (settings.braveApiKey?.trim()) {
|
||||||
|
return settings.braveApiKey.trim()
|
||||||
|
}
|
||||||
|
|
||||||
for (const envVar of BRAVE_API_KEY_ENV_VARS) {
|
for (const envVar of BRAVE_API_KEY_ENV_VARS) {
|
||||||
const value = process.env[envVar]?.trim()
|
const value = process.env[envVar]?.trim()
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|||||||
@@ -43,7 +43,11 @@ export class TavilySearchAdapter implements WebSearchAdapter {
|
|||||||
const settings = getSettings_DEPRECATED() as Record<string, unknown> & {
|
const settings = getSettings_DEPRECATED() as Record<string, unknown> & {
|
||||||
tavilyEndpointUrl?: string
|
tavilyEndpointUrl?: string
|
||||||
}
|
}
|
||||||
const searchUrl = settings.tavilyEndpointUrl || DEFAULT_TAVILY_SEARCH_URL
|
const baseUrl = settings.tavilyEndpointUrl || DEFAULT_TAVILY_SEARCH_URL
|
||||||
|
// Ensure the URL ends with /search (same pattern as fetchContentWithTavily for /extract)
|
||||||
|
const searchUrl = baseUrl.endsWith('/search')
|
||||||
|
? baseUrl
|
||||||
|
: `${baseUrl.replace(/\/$/, '')}/search`
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post<{
|
const response = await axios.post<{
|
||||||
|
|||||||
Reference in New Issue
Block a user