Further updates to web_fetch

This commit is contained in:
Raven Scott
2026-04-22 01:50:59 -04:00
parent b0165c0157
commit 4fc94cebaa
10 changed files with 71 additions and 15 deletions
@@ -77,6 +77,16 @@ function bareWebFmtErrAugment(o, base) {
return tail.length ? base + ' [' + tail.join(', ') + ']' : base
}
/**
* Tool args often omit numeric fields; `Number(undefined)` is NaN and `NaN ?? d` is still NaN.
* @param {unknown} n
* @param {number} def
*/
function bareWebFiniteOr(n, def) {
const x = Number(n)
return Number.isFinite(x) ? x : def
}
/**
* @param {Record<string, unknown>} ctx
* @returns {typeof fetch | null}
@@ -462,13 +472,16 @@ async function bareWebRunTool(o) {
return { ok: false, error: 'web_fetch: only http(s) URLs are allowed' }
}
const maxRedirects = Math.min(Math.max(Number(o.max_redirects) ?? 5, 0), 20)
const maxRedirects = Math.min(
Math.max(bareWebFiniteOr(o.max_redirects, 5), 0),
20
)
const maxBytes = Math.min(
Math.max(Number(o.max_response_bytes) ?? 524288, 1024),
Math.max(bareWebFiniteOr(o.max_response_bytes, 524288), 1024),
2 * 1024 * 1024
)
const timeoutMs = Math.min(
Math.max(Number(o.timeout_ms) ?? 30000, 500),
Math.max(bareWebFiniteOr(o.timeout_ms, 30000), 500),
120000
)
const fmtRaw = String(o.format || 'auto').toLowerCase()
@@ -157,6 +157,23 @@ test('bareWebFmtErr null/undefined and node-like errors', async (t) => {
t.ok(fmt(withCause).includes('inner'))
})
test('bareWebRunTool without timeout_ms uses finite default (not NaN)', async (t) => {
const fetchFn = async () =>
new Response('<html><head><title>ok</title></head></html>', {
status: 200,
headers: { 'Content-Type': 'text/html; charset=utf-8' }
})
const s = loadSandbox({ fetch: fetchFn })
const run = /** @type {typeof bareWebRunTool} */ (s.bareWebRunTool)
const out = await run({
ctx: { httpFetch: fetchFn },
url: 'https://x.test/',
format: 'meta'
})
t.ok(out.ok)
t.absent(JSON.stringify(out).includes('NaN'))
})
test('bareWebRunTool timeout passes abort reason (matches bare-fetch contract)', async (t) => {
/** Simulates bare-fetch: rejects with `signal.reason` when aborted. */
const fetchFn = async (_url, init) => {