From 39a7beb28b7d18fbb8962651817a6741e9ee3794 Mon Sep 17 00:00:00 2001 From: anandgupta42 Date: Tue, 8 Sep 2026 00:30:06 -0700 Subject: [PATCH] fix: Altimate Base header timeout too short (10s) for reasoning backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `altimate-free` loader borrowed the `openai` loader's 10s header timeout (`OPENAI_HEADER_TIMEOUT_DEFAULT`). Altimate Base's gateway holds the HTTP 200 until the backend's first token, and queue wait / cold start / reasoning latency routinely exceeds 10s — so healthy requests aborted with `Provider response headers timed out after 10000ms` (reported on beta.3). - Add `FREE_TIER_HEADER_TIMEOUT_DEFAULT` (`300_000`ms, matching the SSE chunk watchdog `DEFAULT_CHUNK_TIMEOUT`) and use it in the free-tier loader. - Add an `ALTIMATE_BASE_HEADER_TIMEOUT_MS` env override (positive ms, or `0`/`off`/`false`/`none` to disable). The free-tier provider is deliberately excluded from `opencode.json` config merging (`provider.ts` filters `PROVIDER_ID`), so this env var is the only field-tunable override for affected users. - The 5-min `chunkTimeout` still guards mid-stream hangs; the header phase only needs to tolerate the backend's real time-to-first-byte. Root cause is client-side: nginx already streams the completions path (`proxy_buffering off`, `proxy_read_timeout 900s`), so the delay is litellm holding headers until the first upstream token — the client timeout is the correct remedy. Co-Authored-By: Claude Opus 4.8 --- packages/opencode/src/provider/provider.ts | 26 +++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index e74e5500c..797a10c9b 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -83,6 +83,24 @@ const DEFAULT_CHUNK_TIMEOUT = 300_000 const OPENAI_HEADER_TIMEOUT_DEFAULT = 10_000 const HEADER_TIMEOUT = Symbol.for("opencode.provider.header-timeout") // altimate_change end +// altimate_change start — Altimate Base needs a far more generous header timeout than OpenAI. +// Its gateway can queue for a capacity slot, cold-start the backend, or reason before flushing +// response headers — any of which exceeds OpenAI's near-instant reply. OpenAI's 10s default +// therefore false-positives on healthy Altimate Base requests ("Provider response headers timed +// out after 10000ms"). Default to the same 5min the SSE chunk watchdog uses, and expose an env +// override so it is tunable in the field without a release: a positive number of milliseconds, +// or 0/off/false/none to disable the header timeout entirely. +const FREE_TIER_HEADER_TIMEOUT_DEFAULT = 300_000 +function freeTierHeaderTimeout(): number | false { + const raw = Env.get("ALTIMATE_BASE_HEADER_TIMEOUT_MS")?.trim() + if (raw) { + if (["0", "off", "false", "none"].includes(raw.toLowerCase())) return false + const parsed = Number(raw) + if (Number.isFinite(parsed) && parsed > 0) return parsed + } + return FREE_TIER_HEADER_TIMEOUT_DEFAULT +} +// altimate_change end export namespace Provider { const log = Log.create({ service: "provider" }) @@ -393,9 +411,11 @@ export namespace Provider { // authorizedFetch. Provider options are serialized by public provider APIs. apiKey: FreeTier.MANAGED_API_KEY_PLACEHOLDER, fetch: FreeTier.authorizedFetch, - // BUG FIX: without this, a hung gateway response never times out client-side, unlike - // the openai loader below which already sets this. - headerTimeout: OPENAI_HEADER_TIMEOUT_DEFAULT, + // Without a header timeout a hung gateway (connected, never replies) never aborts + // client-side — the SSE chunk watchdog only starts once headers arrive. OpenAI's 10s + // is far too tight for Altimate Base's queue/cold-start/reasoning latency to first + // byte, so use the free tier's generous, env-tunable value instead. + headerTimeout: freeTierHeaderTimeout(), }, } },