mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
fix(timeout): align cc-compatible timeout header with runtime config
This commit is contained in:
@@ -449,6 +449,7 @@ GEMINI_CLI_USER_AGENT=google-api-nodejs-client/9.15.1
|
||||
|
||||
# ── Upstream fetch (provider calls) ──
|
||||
# FETCH_TIMEOUT_MS=600000 # Total request timeout (default: 600000 = 10 min)
|
||||
# # Also drives anthropic-compatible-cc-* X-Stainless-Timeout.
|
||||
# FETCH_HEADERS_TIMEOUT_MS=600000 # Time to receive response headers
|
||||
# FETCH_BODY_TIMEOUT_MS=600000 # Time to receive full response body
|
||||
# FETCH_CONNECT_TIMEOUT_MS=30000 # TCP connection establishment (default: 30s)
|
||||
|
||||
@@ -799,6 +799,8 @@ For most deployments, you only need:
|
||||
|
||||
Backward compatibility is preserved: existing `FETCH_TIMEOUT_MS`, `API_BRIDGE_PROXY_TIMEOUT_MS`, and other per-layer timeout vars still work and override the shared baseline.
|
||||
|
||||
For Claude Code-compatible upstreams (`anthropic-compatible-cc-*`), OmniRoute also derives the outbound `X-Stainless-Timeout` header from the resolved fetch timeout so provider-side read timeouts stay aligned with your env configuration.
|
||||
|
||||
Advanced overrides are available if you need finer control:
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
|
||||
import { getStainlessTimeoutSeconds } from "@/shared/utils/runtimeTimeouts";
|
||||
import { prepareClaudeRequest } from "../translator/helpers/claudeHelper.ts";
|
||||
|
||||
export const CLAUDE_CODE_COMPATIBLE_PREFIX = "anthropic-compatible-cc-";
|
||||
@@ -12,6 +13,9 @@ export const CLAUDE_CODE_COMPATIBLE_ANTHROPIC_BETA =
|
||||
export const CLAUDE_CODE_COMPATIBLE_USER_AGENT = "claude-cli/2.1.89 (external, sdk-cli)";
|
||||
export const CLAUDE_CODE_COMPATIBLE_BILLING_HEADER =
|
||||
"x-anthropic-billing-header: cc_version=2.1.89.728; cc_entrypoint=sdk-cli; cch=00000;";
|
||||
export const CLAUDE_CODE_COMPATIBLE_STAINLESS_TIMEOUT_SECONDS = getStainlessTimeoutSeconds(
|
||||
process.env
|
||||
);
|
||||
|
||||
type HeaderLike =
|
||||
| Headers
|
||||
@@ -97,7 +101,7 @@ export function buildClaudeCodeCompatibleHeaders(
|
||||
"x-app": "cli",
|
||||
"User-Agent": CLAUDE_CODE_COMPATIBLE_USER_AGENT,
|
||||
"X-Stainless-Retry-Count": "0",
|
||||
"X-Stainless-Timeout": "300",
|
||||
"X-Stainless-Timeout": String(CLAUDE_CODE_COMPATIBLE_STAINLESS_TIMEOUT_SECONDS),
|
||||
"X-Stainless-Lang": "js",
|
||||
"X-Stainless-Package-Version": "0.74.0",
|
||||
"X-Stainless-OS": "MacOS",
|
||||
|
||||
@@ -121,6 +121,14 @@ export function getUpstreamTimeoutConfig(
|
||||
};
|
||||
}
|
||||
|
||||
export function getStainlessTimeoutSeconds(
|
||||
env: EnvSource = process.env,
|
||||
logger?: TimeoutLogger
|
||||
): number {
|
||||
const { fetchTimeoutMs } = getUpstreamTimeoutConfig(env, logger);
|
||||
return Math.max(1, Math.ceil(fetchTimeoutMs / 1_000));
|
||||
}
|
||||
|
||||
export function getTlsClientTimeoutConfig(
|
||||
env: EnvSource = process.env,
|
||||
logger?: TimeoutLogger
|
||||
|
||||
@@ -5,6 +5,7 @@ const {
|
||||
CLAUDE_CODE_COMPATIBLE_DEFAULT_CHAT_PATH,
|
||||
CLAUDE_CODE_COMPATIBLE_DEFAULT_MODELS_PATH,
|
||||
CLAUDE_CODE_COMPATIBLE_DEFAULT_MAX_TOKENS,
|
||||
CLAUDE_CODE_COMPATIBLE_STAINLESS_TIMEOUT_SECONDS,
|
||||
isClaudeCodeCompatibleProvider,
|
||||
stripAnthropicMessagesSuffix,
|
||||
stripClaudeCodeCompatibleEndpointSuffix,
|
||||
@@ -46,6 +47,10 @@ test("buildClaudeCodeCompatibleHeaders emits stream-aware auth headers and sessi
|
||||
assert.equal(streamHeaders.Accept, "text/event-stream");
|
||||
assert.equal(streamHeaders["x-api-key"], "sk-demo");
|
||||
assert.equal(streamHeaders["X-Claude-Code-Session-Id"], "session-123");
|
||||
assert.equal(
|
||||
streamHeaders["X-Stainless-Timeout"],
|
||||
String(CLAUDE_CODE_COMPATIBLE_STAINLESS_TIMEOUT_SECONDS)
|
||||
);
|
||||
assert.equal(jsonHeaders.Accept, "application/json");
|
||||
assert.equal(jsonHeaders["X-Claude-Code-Session-Id"], undefined);
|
||||
});
|
||||
|
||||
@@ -65,6 +65,21 @@ test("TLS client timeout defaults to FETCH_TIMEOUT_MS and can be overridden", ()
|
||||
assert.equal(overriddenConfig.timeoutMs, 720000);
|
||||
});
|
||||
|
||||
test("stainless timeout derives from fetch timeout and rounds up to whole seconds", () => {
|
||||
assert.equal(
|
||||
runtimeTimeouts.getStainlessTimeoutSeconds({
|
||||
REQUEST_TIMEOUT_MS: "1200000",
|
||||
}),
|
||||
1200
|
||||
);
|
||||
assert.equal(
|
||||
runtimeTimeouts.getStainlessTimeoutSeconds({
|
||||
FETCH_TIMEOUT_MS: "600001",
|
||||
}),
|
||||
601
|
||||
);
|
||||
});
|
||||
|
||||
test("API bridge timeouts align request timeout with long proxy timeout by default", () => {
|
||||
const config = runtimeTimeouts.getApiBridgeTimeoutConfig({
|
||||
API_BRIDGE_PROXY_TIMEOUT_MS: "600000",
|
||||
|
||||
Reference in New Issue
Block a user