fix(providers): bound native fetch timeouts

This commit is contained in:
Peter Steinberger
2026-04-27 03:33:51 +01:00
parent dc78d58448
commit 348728c28c
5 changed files with 14 additions and 0 deletions

View File

@@ -35,6 +35,7 @@ Docs: https://docs.openclaw.ai
- Providers/Ollama: move memory embeddings to Ollama's current `/api/embed` endpoint with batched `input` requests while preserving vector normalization and custom provider auth/header overrides. Fixes #39983. Thanks @sskkcc and @LiudengZhang.
- Providers/Ollama: route local web search through Ollama's signed `/api/experimental/web_search` daemon proxy, use hosted `/api/web_search` directly for `ollama.com`, and keep `OLLAMA_API_KEY` scoped to cloud fallback auth. Fixes #69132. Thanks @yoon1012 and @hyspacex.
- Providers/Ollama: accept OpenAI SDK-style `baseURL` as an alias for `baseUrl` across discovery, streaming, setup pulls, embeddings, and web search so remote Ollama hosts are not silently ignored. Fixes #62533; supersedes #62549. Thanks @Julien-BKK and @Linux2010.
- Providers/PDF/Ollama: add bounded network timeouts for Ollama model pulls and native Anthropic/Gemini PDF analysis requests so unresponsive provider endpoints no longer hang sessions indefinitely. Fixes #54142; supersedes #54144 and #54145. Thanks @jinduwang1001-max and @arkyu2077.
- Memory/doctor: treat Ollama memory embeddings as key-optional so `openclaw doctor` no longer warns about a missing API key when the gateway reports embeddings are ready. Fixes #46584. Thanks @fengly78.
- Agents/Ollama: apply provider-owned replay turn normalization to native Ollama chat so Cloud models no longer reject non-alternating replay history in agent/Gateway runs. Fixes #71697. Thanks @ismael-81.
- Control UI/Ollama: show the resolved configured thinking default in chat and session thinking dropdowns so inherited `adaptive`/per-model thinking config no longer appears as `Default (off)` or a generic inherit value. Fixes #72407. Thanks @NotecAG.

View File

@@ -417,6 +417,9 @@ describe("ollama setup", () => {
expect(fetchMock).toHaveBeenCalledTimes(2);
expect(fetchMock.mock.calls[1][0]).toContain("/api/pull");
const pullInit = fetchMock.mock.calls[1][1];
expect(pullInit?.signal).toBeInstanceOf(AbortSignal);
expect(pullInit?.signal?.aborted).toBe(false);
});
it("skips pull when model is already available", async () => {

View File

@@ -42,6 +42,7 @@ const OLLAMA_SUGGESTED_MODELS_LOCAL = [OLLAMA_DEFAULT_MODEL];
const OLLAMA_SUGGESTED_MODELS_CLOUD = ["kimi-k2.5:cloud", "minimax-m2.7:cloud", "glm-5.1:cloud"];
const OLLAMA_CONTEXT_ENRICH_LIMIT = 200;
const OLLAMA_CLOUD_MAX_DISCOVERED_MODELS = 500;
const OLLAMA_PULL_REQUEST_TIMEOUT_MS = 30_000;
type OllamaSetupOptions = {
customBaseUrl?: string;
@@ -172,6 +173,7 @@ async function pullOllamaModelCore(params: {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: modelName }),
},
timeoutMs: OLLAMA_PULL_REQUEST_TIMEOUT_MS,
policy: buildOllamaBaseUrlSsrFPolicy(baseUrl),
auditContext: "ollama-setup.pull",
});

View File

@@ -78,6 +78,8 @@ describe("native PDF provider API calls", () => {
expect(fetchMock).toHaveBeenCalledTimes(1);
const [url, opts] = fetchMock.mock.calls[0];
expect(url).toContain("/v1/messages");
expect(opts.signal).toBeInstanceOf(AbortSignal);
expect(opts.signal.aborted).toBe(false);
const body = JSON.parse(opts.body);
expect(body.model).toBe("claude-opus-4-6");
expect(body.messages[0].content).toHaveLength(2);
@@ -132,6 +134,8 @@ describe("native PDF provider API calls", () => {
const [url, opts] = fetchMock.mock.calls[0];
expect(url).toContain("generateContent");
expect(url).toContain("gemini-2.5-pro");
expect(opts.signal).toBeInstanceOf(AbortSignal);
expect(opts.signal.aborted).toBe(false);
const body = JSON.parse(opts.body);
expect(body.contents[0].parts).toHaveLength(2);
expect(body.contents[0].parts[0].inline_data.mime_type).toBe("application/pdf");

View File

@@ -12,6 +12,8 @@ type PdfInput = {
filename?: string;
};
const NATIVE_PDF_PROVIDER_FETCH_TIMEOUT_MS = 120_000;
// ---------------------------------------------------------------------------
// Anthropic native PDF via Messages API
// ---------------------------------------------------------------------------
@@ -74,6 +76,7 @@ export async function anthropicAnalyzePdf(params: {
max_tokens: params.maxTokens ?? 4096,
messages: [{ role: "user", content }],
}),
signal: AbortSignal.timeout(NATIVE_PDF_PROVIDER_FETCH_TIMEOUT_MS),
});
if (!res.ok) {
@@ -158,6 +161,7 @@ export async function geminiAnalyzePdf(params: {
body: JSON.stringify({
contents: [{ role: "user", parts }],
}),
signal: AbortSignal.timeout(NATIVE_PDF_PROVIDER_FETCH_TIMEOUT_MS),
});
if (!res.ok) {