CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
apiPreconnect.ts231 linesDownload Raw Back to utils
1/**2 * @license3 * Copyright 2026 Qwen Team4 * SPDX-License-Identifier: Apache-2.05 */6 7/**8 * API Preconnect - Warm API connections to reduce TCP+TLS handshake latency9 *10 * Principle: Fire a fire-and-forget HEAD request early in startup to warm11 * the TCP+TLS connection. Subsequent actual API calls reuse this connection,12 * saving 100-200ms.13 *14 * The preconnect uses the same shared undici dispatcher as the SDK clients,15 * ensuring the warmed TCP+TLS connection is reused by subsequent API calls.16 */17 18import {19  createDebugLogger,20  detectRuntime,21  getAllProviderBaseUrls,22  getOrCreateSharedDispatcher,23  redactProxyCredentials,24} from '@qwen-code/qwen-code-core';25import { fetch as undiciFetch } from 'undici';26 27const debugLogger = createDebugLogger('PRECONNECT');28 29let preconnectFired = false;30 31/**32 * Default API base URLs by AuthType.33 */34const DEFAULT_BASE_URLS: Record<string, string> = {35  openai: 'https://api.openai.com',36  'qwen-oauth': 'https://coding.dashscope.aliyuncs.com',37  anthropic: 'https://api.anthropic.com',38  dashscope: 'https://dashscope.aliyuncs.com',39};40 41/**42 * All known default base URLs, including all registered provider endpoints.43 * Used by isDefaultBaseUrl() to accept any supported default endpoint.44 */45const ALL_DEFAULT_URLS: string[] = [46  ...Object.values(DEFAULT_BASE_URLS),47  ...getAllProviderBaseUrls(),48];49 50/**51 * Check if preconnect should be skipped due to environment conditions52 */53function shouldSkipPreconnect(): boolean {54  // Skip for custom CA certificate (enterprise TLS inspection may interfere)55  if (process.env['NODE_EXTRA_CA_CERTS']) {56    debugLogger.debug('Skipping preconnect: custom CA certificate configured');57    return true;58  }59 60  return false;61}62 63/**64 * Check if running in sandbox mode65 * In sandbox mode, preconnect is ineffective because the process will restart66 */67function isInSandboxMode(): boolean {68  return process.env['SANDBOX'] !== undefined;69}70 71/**72 * Check if baseUrl is a default URL73 */74function isDefaultBaseUrl(baseUrl: string): boolean {75  const normalizedInput = baseUrl76    .toLowerCase()77    .replace(/^https?:\/\//, '')78    .replace(/\/+$/, '');79  return ALL_DEFAULT_URLS.some((defaultUrl) => {80    const normalizedDefault = defaultUrl81      .toLowerCase()82      .replace(/^https?:\/\//, '')83      .replace(/\/+$/, '');84    return (85      normalizedInput === normalizedDefault ||86      normalizedInput.startsWith(normalizedDefault + '/')87    );88  });89}90 91/**92 * Get the target URL for preconnect.93 * Uses the already-resolved base URL from the model config, falling back94 * to default URLs by authType.95 *96 * Only preconnects to known default URLs — custom URLs may not accept HEAD97 * requests or may require mTLS / private deployment configurations.98 */99function getPreconnectTargetUrl(100  authType: string | undefined,101  resolvedBaseUrl: string | undefined,102): string | undefined {103  // 1. Use the resolved base URL from model config (already incorporates104  //    modelProviders > cli > env > settings priority chain)105  if (resolvedBaseUrl && /^https?:\/\//i.test(resolvedBaseUrl)) {106    if (isDefaultBaseUrl(resolvedBaseUrl)) {107      return resolvedBaseUrl;108    }109    debugLogger.debug(110      'Skipping preconnect: resolved baseUrl is not a default URL',111    );112    return undefined;113  }114 115  // 2. Fall back to default value by authType116  if (authType && DEFAULT_BASE_URLS[authType]) {117    return DEFAULT_BASE_URLS[authType];118  }119 120  return undefined;121}122 123/**124 * Execute API preconnect125 * Use HEAD request to establish TCP+TLS connection without sending actual request body.126 * Uses the shared undici dispatcher to ensure connection pool is shared with SDK clients.127 *128 * @param authType - Authentication type (openai, qwen-oauth, anthropic, etc.)129 * @param options - Configuration options130 */131export function preconnectApi(132  authType: string | undefined,133  options: {134    resolvedBaseUrl?: string;135    proxy?: string;136  } = {},137): void {138  if (preconnectFired) {139    return;140  }141 142  // Check if disabled143  if (process.env['QWEN_CODE_DISABLE_PRECONNECT'] === '1') {144    debugLogger.debug('Preconnect disabled by environment variable');145    preconnectFired = true;146    return;147  }148 149  // Check if in sandbox mode (process will restart, preconnect is ineffective)150  if (isInSandboxMode()) {151    debugLogger.debug('Skipping preconnect: sandbox mode detected');152    preconnectFired = true;153    return;154  }155 156  // Check environment skip conditions (custom CA)157  if (shouldSkipPreconnect()) {158    preconnectFired = true;159    return;160  }161 162  // Skip on non-Node runtimes (e.g. Bun) — they use independent connection163  // pools, so warming undici's pool provides no benefit.164  if (detectRuntime() !== 'node') {165    debugLogger.debug('Skipping preconnect: unsupported runtime');166    preconnectFired = true;167    return;168  }169 170  // Skip dispatcher creation when no proxy configured - SDK uses built-in fetch171  // with its own connection pool, so warming undici dispatcher provides no benefit.172  // This mirrors the logic in buildFetchOptionsWithDispatcher() which also skips173  // custom dispatcher creation when no proxy is set, ensuring consistent behavior.174  if (!options.proxy) {175    debugLogger.debug('Skipping preconnect dispatcher: no proxy configured');176    return;177  }178  const proxy = options.proxy;179 180  const targetUrl = getPreconnectTargetUrl(authType, options.resolvedBaseUrl);181 182  if (!targetUrl) {183    debugLogger.debug('No target URL for preconnect');184    return;185  }186 187  // Mark as fired before async operation — prevents duplicate fires.188  // If the request fails, we don't retry (fire-and-forget semantics).189  preconnectFired = true;190  debugLogger.debug(`Preconnecting to: ${targetUrl}`);191 192  try {193    // Use the same shared undici dispatcher that SDK clients will use,194    // so the warmed TCP+TLS connection is reused by subsequent API calls.195    const dispatcher = getOrCreateSharedDispatcher(proxy);196 197    // Fire HEAD request to warm connection (fire-and-forget).198    // Use undici's own fetch (not Node's built-in fetch) so the dispatcher199    // and fetch come from the same undici version — Node's bundled undici200    // may differ in major version from the bundled one (e.g. v8 vs v6),201    // causing handler-interface mismatches like `invalid onError method`.202    undiciFetch(targetUrl, {203      method: 'HEAD',204      signal: AbortSignal.timeout(5_000),205      headers: {206        'User-Agent': 'QwenCode-Preconnect/1.0',207      },208      dispatcher,209    })210      .then(() => {211        debugLogger.debug('Preconnect completed');212      })213      .catch((error) => {214        const redactedError = redactProxyCredentials(String(error));215        debugLogger.debug(`Preconnect failed (ignored): ${redactedError}`);216      });217  } catch (error) {218    // Preconnect failure doesn't affect main flow219    const redactedError = redactProxyCredentials(String(error));220    debugLogger.debug(`Preconnect failed (ignored): ${redactedError}`);221  }222}223 224/**225 * Reset preconnect state (for testing only)226 * @internal227 */228export function resetPreconnectState(): void {229  preconnectFired = false;230}231 
basant307/AI_Governance_Project · CoolFace