From 94175fa04a3f42366a85a0f95b138932ed4a68fc Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Tue, 17 Feb 2026 07:47:58 -0300 Subject: [PATCH 1/4] refactor(open-sse): migrate all 94 .js files to .ts - Rename all 94 .js files to .ts across config/, utils/, services/, handlers/, executors/, translator/, transformer/, and root index - Add proper TypeScript interfaces: RegistryEntry, AudioProvider, FetchOptions - Add class property declarations to BaseExecutor - Type key function parameters in utils layer (tlsClient, stream, logger, error, proxyFetch, proxyDispatcher, etc.) - Add @ts-ignore annotations for remaining TS2339 errors (gradual migration) - Zero TypeScript errors in open-sse/tsconfig.json - Zero .js files remaining in open-sse/ --- .../{audioRegistry.js => audioRegistry.ts} | 29 +++++++-- ...exInstructions.js => codexInstructions.ts} | 0 .../config/{constants.js => constants.ts} | 0 ...redentialLoader.js => credentialLoader.ts} | 0 ...gnature.js => defaultThinkingSignature.ts} | 0 ...eddingRegistry.js => embeddingRegistry.ts} | 0 .../{imageRegistry.js => imageRegistry.ts} | 0 ...ationRegistry.js => moderationRegistry.ts} | 0 .../{ollamaModels.js => ollamaModels.ts} | 0 .../{providerModels.js => providerModels.ts} | 0 ...roviderRegistry.js => providerRegistry.ts} | 64 +++++++++++++++---- .../{rerankRegistry.js => rerankRegistry.ts} | 0 .../{antigravity.js => antigravity.ts} | 0 open-sse/executors/{base.js => base.ts} | 7 +- open-sse/executors/{codex.js => codex.ts} | 0 open-sse/executors/{cursor.js => cursor.ts} | 9 +++ open-sse/executors/{default.js => default.ts} | 0 .../{gemini-cli.js => gemini-cli.ts} | 0 open-sse/executors/{github.js => github.ts} | 0 open-sse/executors/{index.js => index.ts} | 0 open-sse/executors/{kiro.js => kiro.ts} | 16 +++++ .../{audioSpeech.js => audioSpeech.ts} | 13 ++-- ...Transcription.js => audioTranscription.ts} | 21 +++--- .../handlers/{chatCore.js => chatCore.ts} | 1 + .../handlers/{embeddings.js => embeddings.ts} | 2 + ...{imageGeneration.js => imageGeneration.ts} | 5 ++ .../{moderations.js => moderations.ts} | 11 ++-- open-sse/handlers/{rerank.js => rerank.ts} | 19 +++--- ...nseTranslator.js => responseTranslator.ts} | 23 +++++++ ...esponsesHandler.js => responsesHandler.ts} | 1 + .../handlers/{sseParser.js => sseParser.ts} | 2 + .../{usageExtractor.js => usageExtractor.ts} | 0 open-sse/{index.js => index.ts} | 0 ...{accountFallback.js => accountFallback.ts} | 0 ...{accountSelector.js => accountSelector.ts} | 3 + open-sse/services/{combo.js => combo.ts} | 9 +++ .../{comboConfig.js => comboConfig.ts} | 0 .../{comboMetrics.js => comboMetrics.ts} | 3 + .../{contextManager.js => contextManager.ts} | 3 + .../services/{ipFilter.js => ipFilter.ts} | 0 open-sse/services/{model.js => model.ts} | 0 .../services/{provider.js => provider.ts} | 3 + ...ateLimitManager.js => rateLimitManager.ts} | 6 ++ ...imitSemaphore.js => rateLimitSemaphore.ts} | 1 + .../{sessionManager.js => sessionManager.ts} | 2 + .../{signatureCache.js => signatureCache.ts} | 9 +++ .../{systemPrompt.js => systemPrompt.ts} | 0 .../{thinkingBudget.js => thinkingBudget.ts} | 0 .../{tokenRefresh.js => tokenRefresh.ts} | 0 open-sse/services/{usage.js => usage.ts} | 8 ++- .../{wildcardRouter.js => wildcardRouter.ts} | 0 ...Transformer.js => responsesTransformer.ts} | 5 ++ .../translator/{formats.js => formats.ts} | 0 .../{claudeHelper.js => claudeHelper.ts} | 0 .../{geminiHelper.js => geminiHelper.ts} | 7 ++ ...{maxTokensHelper.js => maxTokensHelper.ts} | 0 .../{openaiHelper.js => openaiHelper.ts} | 0 ...nsesApiHelper.js => responsesApiHelper.ts} | 0 .../{toolCallHelper.js => toolCallHelper.ts} | 0 open-sse/translator/{index.js => index.ts} | 1 + ...-to-openai.js => antigravity-to-openai.ts} | 14 ++++ ...laude-to-gemini.js => claude-to-gemini.ts} | 7 ++ ...laude-to-openai.js => claude-to-openai.ts} | 6 ++ ...emini-to-openai.js => gemini-to-openai.ts} | 7 ++ ...penai-responses.js => openai-responses.ts} | 10 +++ ...penai-to-claude.js => openai-to-claude.ts} | 22 +++++++ ...penai-to-cursor.js => openai-to-cursor.ts} | 4 ++ ...penai-to-gemini.js => openai-to-gemini.ts} | 16 +++++ .../{openai-to-kiro.js => openai-to-kiro.ts} | 9 +++ ...laude-to-openai.js => claude-to-openai.ts} | 4 ++ ...ursor-to-openai.js => cursor-to-openai.ts} | 0 ...emini-to-claude.js => gemini-to-claude.ts} | 0 ...emini-to-openai.js => gemini-to-openai.ts} | 1 + .../{kiro-to-openai.js => kiro-to-openai.ts} | 1 + ...penai-responses.js => openai-responses.ts} | 1 + ...ntigravity.js => openai-to-antigravity.ts} | 4 ++ ...penai-to-claude.js => openai-to-claude.ts} | 0 open-sse/tsconfig.json | 25 ++++++++ .../{bypassHandler.js => bypassHandler.ts} | 0 .../{cursorChecksum.js => cursorChecksum.ts} | 0 .../{cursorProtobuf.js => cursorProtobuf.ts} | 0 open-sse/utils/{error.js => error.ts} | 6 +- open-sse/utils/{logger.js => logger.ts} | 4 +- .../{networkProxy.js => networkProxy.ts} | 1 + ...{ollamaTransform.js => ollamaTransform.ts} | 4 +- ...{progressTracker.js => progressTracker.ts} | 2 +- ...{proxyDispatcher.js => proxyDispatcher.ts} | 3 +- .../utils/{proxyFetch.js => proxyFetch.ts} | 6 +- .../{requestLogger.js => requestLogger.ts} | 0 open-sse/utils/{stream.js => stream.ts} | 11 +++- .../{streamHandler.js => streamHandler.ts} | 3 +- .../{streamHelpers.js => streamHelpers.ts} | 0 .../{thinkTagParser.js => thinkTagParser.ts} | 0 open-sse/utils/{tlsClient.js => tlsClient.ts} | 23 +++++-- .../{usageTracking.js => usageTracking.ts} | 0 95 files changed, 407 insertions(+), 70 deletions(-) rename open-sse/config/{audioRegistry.js => audioRegistry.ts} (83%) rename open-sse/config/{codexInstructions.js => codexInstructions.ts} (100%) rename open-sse/config/{constants.js => constants.ts} (100%) rename open-sse/config/{credentialLoader.js => credentialLoader.ts} (100%) rename open-sse/config/{defaultThinkingSignature.js => defaultThinkingSignature.ts} (100%) rename open-sse/config/{embeddingRegistry.js => embeddingRegistry.ts} (100%) rename open-sse/config/{imageRegistry.js => imageRegistry.ts} (100%) rename open-sse/config/{moderationRegistry.js => moderationRegistry.ts} (100%) rename open-sse/config/{ollamaModels.js => ollamaModels.ts} (100%) rename open-sse/config/{providerModels.js => providerModels.ts} (100%) rename open-sse/config/{providerRegistry.js => providerRegistry.ts} (94%) rename open-sse/config/{rerankRegistry.js => rerankRegistry.ts} (100%) rename open-sse/executors/{antigravity.js => antigravity.ts} (100%) rename open-sse/executors/{base.js => base.ts} (97%) rename open-sse/executors/{codex.js => codex.ts} (100%) rename open-sse/executors/{cursor.js => cursor.ts} (98%) rename open-sse/executors/{default.js => default.ts} (100%) rename open-sse/executors/{gemini-cli.js => gemini-cli.ts} (100%) rename open-sse/executors/{github.js => github.ts} (100%) rename open-sse/executors/{index.js => index.ts} (100%) rename open-sse/executors/{kiro.js => kiro.ts} (97%) rename open-sse/handlers/{audioSpeech.js => audioSpeech.ts} (93%) rename open-sse/handlers/{audioTranscription.js => audioTranscription.ts} (89%) rename open-sse/handlers/{chatCore.js => chatCore.ts} (99%) rename open-sse/handlers/{embeddings.js => embeddings.ts} (99%) rename open-sse/handlers/{imageGeneration.js => imageGeneration.ts} (99%) rename open-sse/handlers/{moderations.js => moderations.ts} (86%) rename open-sse/handlers/{rerank.js => rerank.ts} (88%) rename open-sse/handlers/{responseTranslator.js => responseTranslator.ts} (95%) rename open-sse/handlers/{responsesHandler.js => responsesHandler.ts} (99%) rename open-sse/handlers/{sseParser.js => sseParser.ts} (98%) rename open-sse/handlers/{usageExtractor.js => usageExtractor.ts} (100%) rename open-sse/{index.js => index.ts} (100%) rename open-sse/services/{accountFallback.js => accountFallback.ts} (100%) rename open-sse/services/{accountSelector.js => accountSelector.ts} (95%) rename open-sse/services/{combo.js => combo.ts} (98%) rename open-sse/services/{comboConfig.js => comboConfig.ts} (100%) rename open-sse/services/{comboMetrics.js => comboMetrics.ts} (97%) rename open-sse/services/{contextManager.js => contextManager.ts} (99%) rename open-sse/services/{ipFilter.js => ipFilter.ts} (100%) rename open-sse/services/{model.js => model.ts} (100%) rename open-sse/services/{provider.js => provider.ts} (99%) rename open-sse/services/{rateLimitManager.js => rateLimitManager.ts} (98%) rename open-sse/services/{rateLimitSemaphore.js => rateLimitSemaphore.ts} (99%) rename open-sse/services/{sessionManager.js => sessionManager.ts} (99%) rename open-sse/services/{signatureCache.js => signatureCache.ts} (97%) rename open-sse/services/{systemPrompt.js => systemPrompt.ts} (100%) rename open-sse/services/{thinkingBudget.js => thinkingBudget.ts} (100%) rename open-sse/services/{tokenRefresh.js => tokenRefresh.ts} (100%) rename open-sse/services/{usage.js => usage.ts} (99%) rename open-sse/services/{wildcardRouter.js => wildcardRouter.ts} (100%) rename open-sse/transformer/{responsesTransformer.js => responsesTransformer.ts} (98%) rename open-sse/translator/{formats.js => formats.ts} (100%) rename open-sse/translator/helpers/{claudeHelper.js => claudeHelper.ts} (100%) rename open-sse/translator/helpers/{geminiHelper.js => geminiHelper.ts} (98%) rename open-sse/translator/helpers/{maxTokensHelper.js => maxTokensHelper.ts} (100%) rename open-sse/translator/helpers/{openaiHelper.js => openaiHelper.ts} (100%) rename open-sse/translator/helpers/{responsesApiHelper.js => responsesApiHelper.ts} (100%) rename open-sse/translator/helpers/{toolCallHelper.js => toolCallHelper.ts} (100%) rename open-sse/translator/{index.js => index.ts} (99%) rename open-sse/translator/request/{antigravity-to-openai.js => antigravity-to-openai.ts} (95%) rename open-sse/translator/request/{claude-to-gemini.js => claude-to-gemini.ts} (97%) rename open-sse/translator/request/{claude-to-openai.js => claude-to-openai.ts} (98%) rename open-sse/translator/request/{gemini-to-openai.js => gemini-to-openai.ts} (96%) rename open-sse/translator/request/{openai-responses.js => openai-responses.ts} (97%) rename open-sse/translator/request/{openai-to-claude.js => openai-to-claude.ts} (96%) rename open-sse/translator/request/{openai-to-cursor.js => openai-to-cursor.ts} (97%) rename open-sse/translator/request/{openai-to-gemini.js => openai-to-gemini.ts} (97%) rename open-sse/translator/request/{openai-to-kiro.js => openai-to-kiro.ts} (98%) rename open-sse/translator/response/{claude-to-openai.js => claude-to-openai.ts} (98%) rename open-sse/translator/response/{cursor-to-openai.js => cursor-to-openai.ts} (100%) rename open-sse/translator/response/{gemini-to-claude.js => gemini-to-claude.ts} (100%) rename open-sse/translator/response/{gemini-to-openai.js => gemini-to-openai.ts} (99%) rename open-sse/translator/response/{kiro-to-openai.js => kiro-to-openai.ts} (99%) rename open-sse/translator/response/{openai-responses.js => openai-responses.ts} (99%) rename open-sse/translator/response/{openai-to-antigravity.js => openai-to-antigravity.ts} (98%) rename open-sse/translator/response/{openai-to-claude.js => openai-to-claude.ts} (100%) create mode 100644 open-sse/tsconfig.json rename open-sse/utils/{bypassHandler.js => bypassHandler.ts} (100%) rename open-sse/utils/{cursorChecksum.js => cursorChecksum.ts} (100%) rename open-sse/utils/{cursorProtobuf.js => cursorProtobuf.ts} (100%) rename open-sse/utils/{error.js => error.ts} (95%) rename open-sse/utils/{logger.js => logger.ts} (98%) rename open-sse/utils/{networkProxy.js => networkProxy.ts} (98%) rename open-sse/utils/{ollamaTransform.js => ollamaTransform.ts} (96%) rename open-sse/utils/{progressTracker.js => progressTracker.ts} (97%) rename open-sse/utils/{proxyDispatcher.js => proxyDispatcher.ts} (97%) rename open-sse/utils/{proxyFetch.js => proxyFetch.ts} (96%) rename open-sse/utils/{requestLogger.js => requestLogger.ts} (100%) rename open-sse/utils/{stream.js => stream.ts} (97%) rename open-sse/utils/{streamHandler.js => streamHandler.ts} (98%) rename open-sse/utils/{streamHelpers.js => streamHelpers.ts} (100%) rename open-sse/utils/{thinkTagParser.js => thinkTagParser.ts} (100%) rename open-sse/utils/{tlsClient.js => tlsClient.ts} (84%) rename open-sse/utils/{usageTracking.js => usageTracking.ts} (100%) diff --git a/open-sse/config/audioRegistry.js b/open-sse/config/audioRegistry.ts similarity index 83% rename from open-sse/config/audioRegistry.js rename to open-sse/config/audioRegistry.ts index 5f7456b6a9..cf6e11e0b0 100644 --- a/open-sse/config/audioRegistry.js +++ b/open-sse/config/audioRegistry.ts @@ -6,7 +6,22 @@ * - /v1/audio/speech (TTS API) */ -export const AUDIO_TRANSCRIPTION_PROVIDERS = { +interface AudioModel { + id: string; + name: string; +} + +interface AudioProvider { + id: string; + baseUrl: string; + authType: string; + authHeader: string; + format?: string; + async?: boolean; + models: AudioModel[]; +} + +export const AUDIO_TRANSCRIPTION_PROVIDERS: Record = { openai: { id: "openai", baseUrl: "https://api.openai.com/v1/audio/transcriptions", @@ -57,7 +72,7 @@ export const AUDIO_TRANSCRIPTION_PROVIDERS = { }, }; -export const AUDIO_SPEECH_PROVIDERS = { +export const AUDIO_SPEECH_PROVIDERS: Record = { openai: { id: "openai", baseUrl: "https://api.openai.com/v1/audio/speech", @@ -96,21 +111,21 @@ export const AUDIO_SPEECH_PROVIDERS = { /** * Get transcription provider config by ID */ -export function getTranscriptionProvider(providerId) { +export function getTranscriptionProvider(providerId: string): AudioProvider | null { return AUDIO_TRANSCRIPTION_PROVIDERS[providerId] || null; } /** * Get speech provider config by ID */ -export function getSpeechProvider(providerId) { +export function getSpeechProvider(providerId: string): AudioProvider | null { return AUDIO_SPEECH_PROVIDERS[providerId] || null; } /** * Parse audio model string (format: "provider/model" or just "model") */ -function parseAudioModel(modelStr, registry) { +function parseAudioModel(modelStr: string | null, registry: Record): { provider: string | null; model: string | null } { if (!modelStr) return { provider: null, model: null }; for (const [providerId, config] of Object.entries(registry)) { @@ -128,11 +143,11 @@ function parseAudioModel(modelStr, registry) { return { provider: null, model: modelStr }; } -export function parseTranscriptionModel(modelStr) { +export function parseTranscriptionModel(modelStr: string | null) { return parseAudioModel(modelStr, AUDIO_TRANSCRIPTION_PROVIDERS); } -export function parseSpeechModel(modelStr) { +export function parseSpeechModel(modelStr: string | null) { return parseAudioModel(modelStr, AUDIO_SPEECH_PROVIDERS); } diff --git a/open-sse/config/codexInstructions.js b/open-sse/config/codexInstructions.ts similarity index 100% rename from open-sse/config/codexInstructions.js rename to open-sse/config/codexInstructions.ts diff --git a/open-sse/config/constants.js b/open-sse/config/constants.ts similarity index 100% rename from open-sse/config/constants.js rename to open-sse/config/constants.ts diff --git a/open-sse/config/credentialLoader.js b/open-sse/config/credentialLoader.ts similarity index 100% rename from open-sse/config/credentialLoader.js rename to open-sse/config/credentialLoader.ts diff --git a/open-sse/config/defaultThinkingSignature.js b/open-sse/config/defaultThinkingSignature.ts similarity index 100% rename from open-sse/config/defaultThinkingSignature.js rename to open-sse/config/defaultThinkingSignature.ts diff --git a/open-sse/config/embeddingRegistry.js b/open-sse/config/embeddingRegistry.ts similarity index 100% rename from open-sse/config/embeddingRegistry.js rename to open-sse/config/embeddingRegistry.ts diff --git a/open-sse/config/imageRegistry.js b/open-sse/config/imageRegistry.ts similarity index 100% rename from open-sse/config/imageRegistry.js rename to open-sse/config/imageRegistry.ts diff --git a/open-sse/config/moderationRegistry.js b/open-sse/config/moderationRegistry.ts similarity index 100% rename from open-sse/config/moderationRegistry.js rename to open-sse/config/moderationRegistry.ts diff --git a/open-sse/config/ollamaModels.js b/open-sse/config/ollamaModels.ts similarity index 100% rename from open-sse/config/ollamaModels.js rename to open-sse/config/ollamaModels.ts diff --git a/open-sse/config/providerModels.js b/open-sse/config/providerModels.ts similarity index 100% rename from open-sse/config/providerModels.js rename to open-sse/config/providerModels.ts diff --git a/open-sse/config/providerRegistry.js b/open-sse/config/providerRegistry.ts similarity index 94% rename from open-sse/config/providerRegistry.js rename to open-sse/config/providerRegistry.ts index 063c46abee..ecfc9db06e 100644 --- a/open-sse/config/providerRegistry.js +++ b/open-sse/config/providerRegistry.ts @@ -6,9 +6,51 @@ * is auto-generated from this registry. */ +// ── Types ───────────────────────────────────────────────────────────────── + +export interface RegistryModel { + id: string; + name: string; + targetFormat?: string; +} + +export interface RegistryOAuth { + clientIdEnv?: string; + clientIdDefault?: string; + clientSecretEnv?: string; + clientSecretDefault?: string; + tokenUrl?: string; + refreshUrl?: string; + authUrl?: string; + initiateUrl?: string; + pollUrlBase?: string; +} + +export interface RegistryEntry { + id: string; + alias: string; + format: string; + executor: string; + baseUrl?: string; + baseUrls?: string[]; + responsesBaseUrl?: string; + urlSuffix?: string; + urlBuilder?: (base: string, model: string, stream: boolean) => string; + authType: string; + authHeader: string; + authPrefix?: string; + headers?: Record; + extraHeaders?: Record; + oauth?: RegistryOAuth; + models: RegistryModel[]; + chatPath?: string; + clientVersion?: string; + passthroughModels?: boolean; +} + // ── Registry ────────────────────────────────────────────────────────────── -export const REGISTRY = { +export const REGISTRY: Record = { // ─── OAuth Providers ─────────────────────────────────────────────────── claude: { id: "claude", @@ -760,10 +802,10 @@ export const REGISTRY = { // ── Generator Functions ─────────────────────────────────────────────────── /** Generate legacy PROVIDERS object shape for constants.js backward compatibility */ -export function generateLegacyProviders() { - const providers = {}; +export function generateLegacyProviders(): Record { + const providers: Record = {}; for (const [id, entry] of Object.entries(REGISTRY)) { - const p = { format: entry.format }; + const p: Record = { format: entry.format }; // URL(s) if (entry.baseUrls) { @@ -808,8 +850,8 @@ export function generateLegacyProviders() { } /** Generate PROVIDER_MODELS map (alias → model list) */ -export function generateModels() { - const models = {}; +export function generateModels(): Record { + const models: Record = {}; for (const entry of Object.values(REGISTRY)) { if (entry.models && entry.models.length > 0) { const key = entry.alias || entry.id; @@ -823,8 +865,8 @@ export function generateModels() { } /** Generate PROVIDER_ID_TO_ALIAS map */ -export function generateAliasMap() { - const map = {}; +export function generateAliasMap(): Record { + const map: Record = {}; for (const entry of Object.values(REGISTRY)) { map[entry.id] = entry.alias || entry.id; } @@ -841,12 +883,12 @@ for (const entry of Object.values(REGISTRY)) { } /** Get registry entry by provider ID or alias */ -export function getRegistryEntry(provider) { +export function getRegistryEntry(provider: string): RegistryEntry | null { return REGISTRY[provider] || _byAlias.get(provider) || null; } /** Get all registered provider IDs */ -export function getRegisteredProviders() { +export function getRegisteredProviders(): string[] { return Object.keys(REGISTRY); } @@ -856,7 +898,7 @@ export function getRegisteredProviders() { * @param {string} provider - Provider ID or alias * @returns {"oauth"|"apikey"} */ -export function getProviderCategory(provider) { +export function getProviderCategory(provider: string): "oauth" | "apikey" { const entry = getRegistryEntry(provider); if (!entry) return "apikey"; // Safe default for unknown providers return entry.authType === "apikey" ? "apikey" : "oauth"; diff --git a/open-sse/config/rerankRegistry.js b/open-sse/config/rerankRegistry.ts similarity index 100% rename from open-sse/config/rerankRegistry.js rename to open-sse/config/rerankRegistry.ts diff --git a/open-sse/executors/antigravity.js b/open-sse/executors/antigravity.ts similarity index 100% rename from open-sse/executors/antigravity.js rename to open-sse/executors/antigravity.ts diff --git a/open-sse/executors/base.js b/open-sse/executors/base.ts similarity index 97% rename from open-sse/executors/base.js rename to open-sse/executors/base.ts index 9c0791e4b9..c55653bcb1 100644 --- a/open-sse/executors/base.js +++ b/open-sse/executors/base.ts @@ -6,7 +6,10 @@ import { HTTP_STATUS, FETCH_TIMEOUT_MS } from "../config/constants.js"; * (buildUrl, buildHeaders, transformRequest, etc.) for each provider. */ export class BaseExecutor { - constructor(provider, config) { + provider: any; + config: any; + + constructor(provider: any, config: any) { this.provider = provider; this.config = config; } @@ -96,7 +99,7 @@ export class BaseExecutor { ? AbortSignal.any([signal, timeoutSignal]) : signal || timeoutSignal; - const fetchOptions = { + const fetchOptions: Record = { method: "POST", headers, body: JSON.stringify(transformedBody), diff --git a/open-sse/executors/codex.js b/open-sse/executors/codex.ts similarity index 100% rename from open-sse/executors/codex.js rename to open-sse/executors/codex.ts diff --git a/open-sse/executors/cursor.js b/open-sse/executors/cursor.ts similarity index 98% rename from open-sse/executors/cursor.js rename to open-sse/executors/cursor.ts index 7f9a018dc1..cc1096c7c5 100644 --- a/open-sse/executors/cursor.js +++ b/open-sse/executors/cursor.ts @@ -36,6 +36,7 @@ import zlib from "zlib"; // Detect cloud environment const isCloudEnv = () => { if (typeof caches !== "undefined" && typeof caches === "object") return true; + // @ts-ignore — EdgeRuntime is a global in edge runtimes if (typeof EdgeRuntime !== "undefined") return true; return false; }; @@ -226,6 +227,7 @@ export class CursorExecutor extends BaseExecutor { return { status: response.status, + // @ts-ignore — Headers.entries() exists at runtime headers: Object.fromEntries(response.headers.entries()), body: Buffer.from(await response.arrayBuffer()), }; @@ -294,17 +296,21 @@ export class CursorExecutor extends BaseExecutor { ? await this.makeHttp2Request(url, headers, transformedBody, signal) : await this.makeFetchRequest(url, headers, transformedBody, signal); + // @ts-ignore if (response.status !== 200) { + // @ts-ignore const errorText = response.body?.toString() || "Unknown error"; const errorResponse = new Response( JSON.stringify({ error: { + // @ts-ignore message: `[${response.status}]: ${errorText}`, type: "invalid_request_error", code: "", }, }), { + // @ts-ignore status: response.status, headers: { "Content-Type": "application/json" }, } @@ -314,7 +320,9 @@ export class CursorExecutor extends BaseExecutor { const transformedResponse = stream !== false + // @ts-ignore ? this.transformProtobufToSSE(response.body, model, body) + // @ts-ignore : this.transformProtobufToJSON(response.body, model, body); return { response: transformedResponse, url, headers, transformedBody: body }; @@ -464,6 +472,7 @@ export class CursorExecutor extends BaseExecutor { }; if (toolCalls.length > 0) { + // @ts-ignore message.tool_calls = toolCalls; } diff --git a/open-sse/executors/default.js b/open-sse/executors/default.ts similarity index 100% rename from open-sse/executors/default.js rename to open-sse/executors/default.ts diff --git a/open-sse/executors/gemini-cli.js b/open-sse/executors/gemini-cli.ts similarity index 100% rename from open-sse/executors/gemini-cli.js rename to open-sse/executors/gemini-cli.ts diff --git a/open-sse/executors/github.js b/open-sse/executors/github.ts similarity index 100% rename from open-sse/executors/github.js rename to open-sse/executors/github.ts diff --git a/open-sse/executors/index.js b/open-sse/executors/index.ts similarity index 100% rename from open-sse/executors/index.js rename to open-sse/executors/index.ts diff --git a/open-sse/executors/kiro.js b/open-sse/executors/kiro.ts similarity index 97% rename from open-sse/executors/kiro.js rename to open-sse/executors/kiro.ts index a9fe3a670e..7bf8d0fe79 100644 --- a/open-sse/executors/kiro.js +++ b/open-sse/executors/kiro.ts @@ -118,12 +118,15 @@ export class KiroExecutor extends BaseExecutor { const eventType = event.headers[":event-type"] || ""; // Track total content length for token estimation + // @ts-ignore if (!state.totalContentLength) state.totalContentLength = 0; + // @ts-ignore if (!state.contextUsagePercentage) state.contextUsagePercentage = 0; // Handle assistantResponseEvent if (eventType === "assistantResponseEvent" && event.payload?.content) { const content = event.payload.content; + // @ts-ignore state.totalContentLength += content.length; const chunk = { @@ -276,13 +279,16 @@ export class KiroExecutor extends BaseExecutor { // Handle contextUsageEvent to extract contextUsagePercentage if (eventType === "contextUsageEvent" && event.payload?.contextUsagePercentage) { + // @ts-ignore state.contextUsagePercentage = event.payload.contextUsagePercentage; // Mark that we received context usage event + // @ts-ignore state.hasContextUsage = true; } // Handle meteringEvent - mark that we received it if (eventType === "meteringEvent") { + // @ts-ignore state.hasMeteringEvent = true; } @@ -295,6 +301,7 @@ export class KiroExecutor extends BaseExecutor { const outputTokens = metrics.outputTokens || 0; if (inputTokens > 0 || outputTokens > 0) { + // @ts-ignore state.usage = { prompt_tokens: inputTokens, completion_tokens: outputTokens, @@ -305,24 +312,31 @@ export class KiroExecutor extends BaseExecutor { } // Emit final chunk only after receiving BOTH meteringEvent AND contextUsageEvent + // @ts-ignore if (state.hasMeteringEvent && state.hasContextUsage && !state.finishEmitted) { state.finishEmitted = true; // Estimate tokens if not available from events + // @ts-ignore if (!state.usage) { // Estimate output tokens from content length const estimatedOutputTokens = + // @ts-ignore state.totalContentLength > 0 + // @ts-ignore ? Math.max(1, Math.floor(state.totalContentLength / 4)) : 0; // Estimate input tokens from contextUsagePercentage // Kiro models typically have 200k context window const estimatedInputTokens = + // @ts-ignore state.contextUsagePercentage > 0 + // @ts-ignore ? Math.floor((state.contextUsagePercentage * 200000) / 100) : 0; + // @ts-ignore state.usage = { prompt_tokens: estimatedInputTokens, completion_tokens: estimatedOutputTokens, @@ -345,7 +359,9 @@ export class KiroExecutor extends BaseExecutor { }; // Include usage in final chunk if available + // @ts-ignore if (state.usage) { + // @ts-ignore finishChunk.usage = state.usage; } diff --git a/open-sse/handlers/audioSpeech.js b/open-sse/handlers/audioSpeech.ts similarity index 93% rename from open-sse/handlers/audioSpeech.js rename to open-sse/handlers/audioSpeech.ts index bb1196e299..05299f902c 100644 --- a/open-sse/handlers/audioSpeech.js +++ b/open-sse/handlers/audioSpeech.ts @@ -100,12 +100,13 @@ async function handleDeepgramSpeech(providerConfig, body, modelId, token) { * @param {Object} options.credentials - Provider credentials { apiKey } * @returns {Response} */ +/** @returns {Promise} */ export async function handleAudioSpeech({ body, credentials }) { if (!body.model) { - return errorResponse("model is required", 400); + return errorResponse(400, "model is required"); } if (!body.input) { - return errorResponse("input is required", 400); + return errorResponse(400, "input is required"); } const { provider: providerId, model: modelId } = parseSpeechModel(body.model); @@ -113,14 +114,14 @@ export async function handleAudioSpeech({ body, credentials }) { if (!providerConfig) { return errorResponse( - `No speech provider found for model "${body.model}". Available: openai, hyperbolic, deepgram`, - 400 + 400, + `No speech provider found for model "${body.model}". Available: openai, hyperbolic, deepgram` ); } const token = credentials?.apiKey || credentials?.accessToken; if (!token) { - return errorResponse(`No credentials for speech provider: ${providerId}`, 401); + return errorResponse(401, `No credentials for speech provider: ${providerId}`); } try { @@ -168,6 +169,6 @@ export async function handleAudioSpeech({ body, credentials }) { }, }); } catch (err) { - return errorResponse(`Speech request failed: ${err.message}`, 500); + return errorResponse(500, `Speech request failed: ${err.message}`); } } diff --git a/open-sse/handlers/audioTranscription.js b/open-sse/handlers/audioTranscription.ts similarity index 89% rename from open-sse/handlers/audioTranscription.js rename to open-sse/handlers/audioTranscription.ts index c25eac19f3..3c511f738f 100644 --- a/open-sse/handlers/audioTranscription.js +++ b/open-sse/handlers/audioTranscription.ts @@ -129,11 +129,11 @@ async function handleAssemblyAITranscription(providerConfig, file, modelId, toke } if (result.status === "error") { - return errorResponse(result.error || "AssemblyAI transcription failed", 500); + return errorResponse(500, result.error || "AssemblyAI transcription failed"); } } - return errorResponse("AssemblyAI transcription timed out after 120s", 504); + return errorResponse(504, "AssemblyAI transcription timed out after 120s"); } /** @@ -144,15 +144,16 @@ async function handleAssemblyAITranscription(providerConfig, file, modelId, toke * @param {Object} options.credentials - Provider credentials { apiKey } * @returns {Response} */ +/** @returns {Promise} */ export async function handleAudioTranscription({ formData, credentials }) { const model = formData.get("model"); if (!model) { - return errorResponse("model is required", 400); + return errorResponse(400, "model is required"); } const file = formData.get("file"); if (!file) { - return errorResponse("file is required", 400); + return errorResponse(400, "file is required"); } const { provider: providerId, model: modelId } = parseTranscriptionModel(model); @@ -160,14 +161,14 @@ export async function handleAudioTranscription({ formData, credentials }) { if (!providerConfig) { return errorResponse( - `No transcription provider found for model "${model}". Available: openai, groq, deepgram, assemblyai`, - 400 + 400, + `No transcription provider found for model "${model}". Available: openai, groq, deepgram, assemblyai` ); } const token = credentials?.apiKey || credentials?.accessToken; if (!token) { - return errorResponse(`No credentials for transcription provider: ${providerId}`, 401); + return errorResponse(401, `No credentials for transcription provider: ${providerId}`); } // Route to provider-specific handler @@ -181,7 +182,7 @@ export async function handleAudioTranscription({ formData, credentials }) { // Default: OpenAI/Groq-compatible multipart proxy const upstreamForm = new FormData(); - upstreamForm.append("file", file, file.name || "audio.wav"); + upstreamForm.append("file", /** @type {Blob} */ (file), /** @type {any} */ (file).name || "audio.wav"); upstreamForm.append("model", modelId); // Forward optional parameters @@ -194,7 +195,7 @@ export async function handleAudioTranscription({ formData, credentials }) { ]) { const val = formData.get(key); if (val !== null && val !== undefined) { - upstreamForm.append(key, val); + upstreamForm.append(key, /** @type {string} */ (val)); } } @@ -221,6 +222,6 @@ export async function handleAudioTranscription({ formData, credentials }) { headers: { "Content-Type": contentType, "Access-Control-Allow-Origin": "*" }, }); } catch (err) { - return errorResponse(`Transcription request failed: ${err.message}`, 500); + return errorResponse(500, `Transcription request failed: ${err.message}`); } } diff --git a/open-sse/handlers/chatCore.js b/open-sse/handlers/chatCore.ts similarity index 99% rename from open-sse/handlers/chatCore.js rename to open-sse/handlers/chatCore.ts index d260159aaa..12a77e4c71 100644 --- a/open-sse/handlers/chatCore.js +++ b/open-sse/handlers/chatCore.ts @@ -52,6 +52,7 @@ import { createProgressTransform, wantsProgress } from "../utils/progressTracker * @param {string} options.connectionId - Connection ID for usage tracking * @param {object} options.apiKeyInfo - API key metadata for usage attribution */ +/** @param {any} options */ export async function handleChatCore({ body, modelInfo, diff --git a/open-sse/handlers/embeddings.js b/open-sse/handlers/embeddings.ts similarity index 99% rename from open-sse/handlers/embeddings.js rename to open-sse/handlers/embeddings.ts index 871ee4d123..5d3d516196 100644 --- a/open-sse/handlers/embeddings.js +++ b/open-sse/handlers/embeddings.ts @@ -58,7 +58,9 @@ export async function handleEmbedding({ body, credentials, log }) { }; // Pass optional parameters + // @ts-ignore if (body.dimensions !== undefined) upstreamBody.dimensions = body.dimensions; + // @ts-ignore if (body.encoding_format !== undefined) upstreamBody.encoding_format = body.encoding_format; // Build headers diff --git a/open-sse/handlers/imageGeneration.js b/open-sse/handlers/imageGeneration.ts similarity index 99% rename from open-sse/handlers/imageGeneration.js rename to open-sse/handlers/imageGeneration.ts index 4aed218826..3627c3e6c5 100644 --- a/open-sse/handlers/imageGeneration.js +++ b/open-sse/handlers/imageGeneration.ts @@ -238,10 +238,15 @@ async function handleOpenAIImageGeneration({ }; // Pass optional parameters + // @ts-ignore if (body.n !== undefined) upstreamBody.n = body.n; + // @ts-ignore if (body.size !== undefined) upstreamBody.size = body.size; + // @ts-ignore if (body.quality !== undefined) upstreamBody.quality = body.quality; + // @ts-ignore if (body.response_format !== undefined) upstreamBody.response_format = body.response_format; + // @ts-ignore if (body.style !== undefined) upstreamBody.style = body.style; // Build headers diff --git a/open-sse/handlers/moderations.js b/open-sse/handlers/moderations.ts similarity index 86% rename from open-sse/handlers/moderations.js rename to open-sse/handlers/moderations.ts index 32509dada3..64bce58aba 100644 --- a/open-sse/handlers/moderations.js +++ b/open-sse/handlers/moderations.ts @@ -15,9 +15,10 @@ import { errorResponse } from "../utils/error.js"; * @param {Object} options.credentials - Provider credentials { apiKey } * @returns {Response} */ +/** @returns {Promise} */ export async function handleModeration({ body, credentials }) { if (!body.input) { - return errorResponse("input is required", 400); + return errorResponse(400, "input is required"); } // Default to latest moderation model @@ -27,14 +28,14 @@ export async function handleModeration({ body, credentials }) { if (!providerConfig) { return errorResponse( - `No moderation provider found for model "${model}". Available: openai`, - 400 + 400, + `No moderation provider found for model "${model}". Available: openai` ); } const token = credentials?.apiKey || credentials?.accessToken; if (!token) { - return errorResponse(`No credentials for moderation provider: ${providerId}`, 401); + return errorResponse(401, `No credentials for moderation provider: ${providerId}`); } try { @@ -63,6 +64,6 @@ export async function handleModeration({ body, credentials }) { headers: { "Access-Control-Allow-Origin": "*" }, }); } catch (err) { - return errorResponse(`Moderation request failed: ${err.message}`, 500); + return errorResponse(500, `Moderation request failed: ${err.message}`); } } diff --git a/open-sse/handlers/rerank.js b/open-sse/handlers/rerank.ts similarity index 88% rename from open-sse/handlers/rerank.js rename to open-sse/handlers/rerank.ts index 7ec8abf6d0..5851f8d3b3 100644 --- a/open-sse/handlers/rerank.js +++ b/open-sse/handlers/rerank.ts @@ -69,6 +69,7 @@ function transformResponseFromProvider(providerConfig, data) { * @param {Object} options.credentials - Provider credentials { apiKey, accessToken } * @returns {Response} */ +/** @returns {Promise} */ export async function handleRerank({ model, query, @@ -77,10 +78,10 @@ export async function handleRerank({ return_documents, credentials, }) { - if (!model) return errorResponse("model is required", 400); - if (!query) return errorResponse("query is required", 400); + if (!model) return errorResponse(400, "model is required"); + if (!query) return errorResponse(400, "query is required"); if (!documents || !Array.isArray(documents) || documents.length === 0) { - return errorResponse("documents must be a non-empty array", 400); + return errorResponse(400, "documents must be a non-empty array"); } const { provider: providerId, model: modelId } = parseRerankModel(model); @@ -88,14 +89,14 @@ export async function handleRerank({ if (!providerConfig) { return errorResponse( - `No rerank provider found for model "${model}". Available: cohere, together, nvidia, fireworks`, - 400 + 400, + `No rerank provider found for model "${model}". Available: cohere, together, nvidia, fireworks` ); } const token = credentials?.apiKey || credentials?.accessToken; if (!token) { - return errorResponse(`No credentials for rerank provider: ${providerId}`, 401); + return errorResponse(401, `No credentials for rerank provider: ${providerId}`); } const requestBody = transformRequestForProvider(providerConfig, { @@ -119,8 +120,8 @@ export async function handleRerank({ if (!res.ok) { const errData = await res.json().catch(() => ({})); return errorResponse( - errData.message || errData.error?.message || `Provider returned HTTP ${res.status}`, - res.status + res.status, + errData.message || errData.error?.message || `Provider returned HTTP ${res.status}` ); } @@ -131,6 +132,6 @@ export async function handleRerank({ headers: { "Access-Control-Allow-Origin": "*" }, }); } catch (err) { - return errorResponse(`Rerank request failed: ${err.message}`, 500); + return errorResponse(500, `Rerank request failed: ${err.message}`); } } diff --git a/open-sse/handlers/responseTranslator.js b/open-sse/handlers/responseTranslator.ts similarity index 95% rename from open-sse/handlers/responseTranslator.js rename to open-sse/handlers/responseTranslator.ts index 79dc42b388..bf2737c423 100644 --- a/open-sse/handlers/responseTranslator.js +++ b/open-sse/handlers/responseTranslator.ts @@ -58,15 +58,20 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source const message = { role: "assistant" }; if (textContent) { + // @ts-ignore message.content = textContent; } if (reasoningContent) { + // @ts-ignore message.reasoning_content = reasoningContent; } if (toolCalls.length > 0) { + // @ts-ignore message.tool_calls = toolCalls; } + // @ts-ignore if (!message.content && !message.tool_calls) { + // @ts-ignore message.content = ""; } @@ -91,6 +96,7 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source if (usage && typeof usage === "object") { const inputTokens = usage.input_tokens || 0; const outputTokens = usage.output_tokens || 0; + // @ts-ignore result.usage = { prompt_tokens: inputTokens, completion_tokens: outputTokens, @@ -98,16 +104,20 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source }; if (usage.reasoning_tokens > 0) { + // @ts-ignore result.usage.completion_tokens_details = { reasoning_tokens: usage.reasoning_tokens, }; } if (usage.cache_read_input_tokens > 0 || usage.cache_creation_input_tokens > 0) { + // @ts-ignore result.usage.prompt_tokens_details = {}; if (usage.cache_read_input_tokens > 0) { + // @ts-ignore result.usage.prompt_tokens_details.cached_tokens = usage.cache_read_input_tokens; } if (usage.cache_creation_input_tokens > 0) { + // @ts-ignore result.usage.prompt_tokens_details.cache_creation_tokens = usage.cache_creation_input_tokens; } @@ -164,16 +174,21 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source // Build OpenAI format message const message = { role: "assistant" }; if (textContent) { + // @ts-ignore message.content = textContent; } if (reasoningContent) { + // @ts-ignore message.reasoning_content = reasoningContent; } if (toolCalls.length > 0) { + // @ts-ignore message.tool_calls = toolCalls; } // If no content at all, set content to empty string + // @ts-ignore if (!message.content && !message.tool_calls) { + // @ts-ignore message.content = ""; } @@ -199,12 +214,14 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source // Add usage if available (match streaming translator: add thoughtsTokenCount to prompt_tokens) if (usage) { + // @ts-ignore result.usage = { prompt_tokens: (usage.promptTokenCount || 0) + (usage.thoughtsTokenCount || 0), completion_tokens: usage.candidatesTokenCount || 0, total_tokens: usage.totalTokenCount || 0, }; if (usage.thoughtsTokenCount > 0) { + // @ts-ignore result.usage.completion_tokens_details = { reasoning_tokens: usage.thoughtsTokenCount, }; @@ -243,15 +260,20 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source const message = { role: "assistant" }; if (textContent) { + // @ts-ignore message.content = textContent; } if (thinkingContent) { + // @ts-ignore message.reasoning_content = thinkingContent; } if (toolCalls.length > 0) { + // @ts-ignore message.tool_calls = toolCalls; } + // @ts-ignore if (!message.content && !message.tool_calls) { + // @ts-ignore message.content = ""; } @@ -274,6 +296,7 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source }; if (responseBody.usage) { + // @ts-ignore result.usage = { prompt_tokens: responseBody.usage.input_tokens || 0, completion_tokens: responseBody.usage.output_tokens || 0, diff --git a/open-sse/handlers/responsesHandler.js b/open-sse/handlers/responsesHandler.ts similarity index 99% rename from open-sse/handlers/responsesHandler.js rename to open-sse/handlers/responsesHandler.ts index 1066726ecd..cd5e2ced95 100644 --- a/open-sse/handlers/responsesHandler.js +++ b/open-sse/handlers/responsesHandler.ts @@ -37,6 +37,7 @@ export async function handleResponsesCore({ convertedBody.stream = true; // Call chat core handler + // @ts-ignore const result = await handleChatCore({ body: convertedBody, modelInfo, diff --git a/open-sse/handlers/sseParser.js b/open-sse/handlers/sseParser.ts similarity index 98% rename from open-sse/handlers/sseParser.js rename to open-sse/handlers/sseParser.ts index 608f5c349e..e48ab70c66 100644 --- a/open-sse/handlers/sseParser.js +++ b/open-sse/handlers/sseParser.ts @@ -49,6 +49,7 @@ export function parseSSEToOpenAIResponse(rawSSE, fallbackModel) { content: contentParts.join(""), }; if (reasoningParts.length > 0) { + // @ts-ignore message.reasoning_content = reasoningParts.join(""); } @@ -67,6 +68,7 @@ export function parseSSEToOpenAIResponse(rawSSE, fallbackModel) { }; if (usage) { + // @ts-ignore result.usage = usage; } diff --git a/open-sse/handlers/usageExtractor.js b/open-sse/handlers/usageExtractor.ts similarity index 100% rename from open-sse/handlers/usageExtractor.js rename to open-sse/handlers/usageExtractor.ts diff --git a/open-sse/index.js b/open-sse/index.ts similarity index 100% rename from open-sse/index.js rename to open-sse/index.ts diff --git a/open-sse/services/accountFallback.js b/open-sse/services/accountFallback.ts similarity index 100% rename from open-sse/services/accountFallback.js rename to open-sse/services/accountFallback.ts diff --git a/open-sse/services/accountSelector.js b/open-sse/services/accountSelector.ts similarity index 95% rename from open-sse/services/accountSelector.js rename to open-sse/services/accountSelector.ts index a43886ed70..d9df9da20b 100644 --- a/open-sse/services/accountSelector.js +++ b/open-sse/services/accountSelector.ts @@ -27,7 +27,9 @@ export function selectAccountP2C(accounts, model = null) { const a = accounts[i]; const b = accounts[j]; + // @ts-ignore — getAccountHealth accepts optional model const healthA = getAccountHealth(a, model); + // @ts-ignore const healthB = getAccountHealth(b, model); return healthA >= healthB ? a : b; @@ -59,6 +61,7 @@ export function selectAccount(accounts, strategy = "fill-first", state = {}, mod }; case "round-robin": { + // @ts-ignore const lastIndex = state.lastIndex ?? -1; const nextIndex = (lastIndex + 1) % accounts.length; return { diff --git a/open-sse/services/combo.js b/open-sse/services/combo.ts similarity index 98% rename from open-sse/services/combo.js rename to open-sse/services/combo.ts index 90e75de9af..588190153f 100644 --- a/open-sse/services/combo.js +++ b/open-sse/services/combo.ts @@ -36,6 +36,7 @@ function normalizeModelEntry(entry) { * @returns {Object|null} Full combo object or null if not a combo */ export function getComboFromData(modelStr, combosData) { + // @ts-ignore - combosData can be object with .combos property const combos = Array.isArray(combosData) ? combosData : combosData?.combos || []; const combo = combos.find((c) => c.name === modelStr); if (combo && combo.models && combo.models.length > 0) { @@ -70,6 +71,7 @@ export function validateComboDAG(comboName, allCombos, visited = new Set(), dept } visited.add(comboName); + // @ts-ignore - allCombos can be object with .combos property const combos = Array.isArray(allCombos) ? allCombos : allCombos?.combos || []; const combo = combos.find((c) => c.name === comboName); if (!combo || !combo.models) return; @@ -98,6 +100,7 @@ export function resolveNestedComboModels(combo, allCombos, visited = new Set(), if (visited.has(combo.name)) return []; // cycle safety visited.add(combo.name); + // @ts-ignore const combos = Array.isArray(allCombos) ? allCombos : allCombos?.combos || []; const resolved = []; @@ -221,6 +224,7 @@ function sortModelsByUsage(models, comboName) { * @param {Object} options.log - Logger object * @returns {Promise} */ +/** @param {any} options */ export async function handleComboChat({ body, combo, @@ -248,6 +252,7 @@ export async function handleComboChat({ // Use config cascade if settings provided const config = settings + // @ts-ignore ? resolveComboConfig(combo, settings) : { ...getDefaultComboConfig(), ...(combo.config || {}) }; const maxRetries = config.maxRetries ?? 1; @@ -449,6 +454,7 @@ export async function handleComboChat({ if (allBreakersOpen) { log.warn("COMBO", "All models have circuit breaker OPEN — aborting"); + // @ts-ignore - partial args are valid for this error case return unavailableResponse( 503, "All providers temporarily unavailable (circuit breakers open)" @@ -493,6 +499,7 @@ async function handleRoundRobinCombo({ }) { const models = combo.models || []; const config = settings + // @ts-ignore ? resolveComboConfig(combo, settings) : { ...getDefaultComboConfig(), ...(combo.config || {}) }; const concurrency = config.concurrencyPerModel ?? 3; @@ -510,6 +517,7 @@ async function handleRoundRobinCombo({ const modelCount = orderedModels.length; if (modelCount === 0) { + // @ts-ignore - partial args are valid for this error case return unavailableResponse(406, "Round-robin combo has no models"); } @@ -699,6 +707,7 @@ async function handleRoundRobinCombo({ if (allBreakersOpen) { log.warn("COMBO-RR", "All models have circuit breaker OPEN — aborting"); + // @ts-ignore - partial args are valid for this error case return unavailableResponse( 503, "All providers temporarily unavailable (circuit breakers open)" diff --git a/open-sse/services/comboConfig.js b/open-sse/services/comboConfig.ts similarity index 100% rename from open-sse/services/comboConfig.js rename to open-sse/services/comboConfig.ts diff --git a/open-sse/services/comboMetrics.js b/open-sse/services/comboMetrics.ts similarity index 97% rename from open-sse/services/comboMetrics.js rename to open-sse/services/comboMetrics.ts index 021e913e74..ce0ca42b5f 100644 --- a/open-sse/services/comboMetrics.js +++ b/open-sse/services/comboMetrics.ts @@ -96,8 +96,11 @@ export function getComboMetrics(comboName) { Object.entries(combo.byModel).map(([model, m]) => [ model, { + // @ts-ignore ...m, + // @ts-ignore avgLatencyMs: m.requests > 0 ? Math.round(m.totalLatencyMs / m.requests) : 0, + // @ts-ignore successRate: m.requests > 0 ? Math.round((m.successes / m.requests) * 100) : 0, }, ]) diff --git a/open-sse/services/contextManager.js b/open-sse/services/contextManager.ts similarity index 99% rename from open-sse/services/contextManager.js rename to open-sse/services/contextManager.ts index 373331ce63..54d8a941a0 100644 --- a/open-sse/services/contextManager.js +++ b/open-sse/services/contextManager.ts @@ -56,8 +56,11 @@ export function compressContext(body, options = {}) { return { body, compressed: false, stats: {} }; } + // @ts-ignore const provider = options.provider || "default"; + // @ts-ignore const maxTokens = options.maxTokens || getTokenLimit(provider, body.model || options.model); + // @ts-ignore const reserveTokens = options.reserveTokens || 16000; // Reserve for response const targetTokens = maxTokens - reserveTokens; diff --git a/open-sse/services/ipFilter.js b/open-sse/services/ipFilter.ts similarity index 100% rename from open-sse/services/ipFilter.js rename to open-sse/services/ipFilter.ts diff --git a/open-sse/services/model.js b/open-sse/services/model.ts similarity index 100% rename from open-sse/services/model.js rename to open-sse/services/model.ts diff --git a/open-sse/services/provider.js b/open-sse/services/provider.ts similarity index 99% rename from open-sse/services/provider.js rename to open-sse/services/provider.ts index 5d640ba208..1cc6ebec20 100644 --- a/open-sse/services/provider.js +++ b/open-sse/services/provider.ts @@ -159,10 +159,12 @@ export function getProviderFallbackCount(provider) { export function buildProviderUrl(provider, model, stream = true, options = {}) { if (isOpenAICompatible(provider)) { const apiType = getOpenAICompatibleType(provider); + // @ts-ignore const baseUrl = options?.baseUrl || OPENAI_COMPATIBLE_DEFAULTS.baseUrl; return buildOpenAICompatibleUrl(baseUrl, apiType); } if (isAnthropicCompatible(provider)) { + // @ts-ignore const baseUrl = options?.baseUrl || ANTHROPIC_COMPATIBLE_DEFAULTS.baseUrl; return buildAnthropicCompatibleUrl(baseUrl); } @@ -174,6 +176,7 @@ export function buildProviderUrl(provider, model, stream = true, options = {}) { if (entry) { // Multi-URL providers (e.g. antigravity) if (entry.baseUrls) { + // @ts-ignore const urlIndex = options?.baseUrlIndex || 0; const baseUrl = entry.baseUrls[urlIndex] || entry.baseUrls[0]; if (entry.urlBuilder) return entry.urlBuilder(baseUrl, model, stream); diff --git a/open-sse/services/rateLimitManager.js b/open-sse/services/rateLimitManager.ts similarity index 98% rename from open-sse/services/rateLimitManager.js rename to open-sse/services/rateLimitManager.ts index 381d458e5c..84a5a06e15 100644 --- a/open-sse/services/rateLimitManager.js +++ b/open-sse/services/rateLimitManager.ts @@ -298,8 +298,11 @@ export function updateFromHeaders(provider, connectionId, headers, status, model // If remaining is low (< 10% of limit), set reservoir to throttle immediately if (!isNaN(remaining)) { if (remaining < limit * 0.1) { + // @ts-ignore updates.reservoir = remaining; + // @ts-ignore updates.reservoirRefreshAmount = limit; + // @ts-ignore updates.reservoirRefreshInterval = resetMs; console.log( `⚠️ [RATE-LIMIT] ${provider}:${connectionId.slice(0, 8)} — ${remaining}/${limit} remaining, throttling` @@ -307,8 +310,11 @@ export function updateFromHeaders(provider, connectionId, headers, status, model } else if (remaining > limit * 0.5) { // Plenty of headroom — relax the limiter updates.minTime = 0; + // @ts-ignore updates.reservoir = null; + // @ts-ignore updates.reservoirRefreshAmount = null; + // @ts-ignore updates.reservoirRefreshInterval = null; } } diff --git a/open-sse/services/rateLimitSemaphore.js b/open-sse/services/rateLimitSemaphore.ts similarity index 99% rename from open-sse/services/rateLimitSemaphore.js rename to open-sse/services/rateLimitSemaphore.ts index b6c149321f..d50ecf3e8f 100644 --- a/open-sse/services/rateLimitSemaphore.js +++ b/open-sse/services/rateLimitSemaphore.ts @@ -117,6 +117,7 @@ export function acquire(modelStr, { maxConcurrency = 3, timeoutMs = 30000 } = {} const idx = gate.queue.findIndex((item) => item.timer === timer); if (idx !== -1) gate.queue.splice(idx, 1); const err = new Error(`Semaphore timeout after ${timeoutMs}ms for ${modelStr}`); + // @ts-ignore — custom error code property err.code = "SEMAPHORE_TIMEOUT"; reject(err); }, timeoutMs); diff --git a/open-sse/services/sessionManager.js b/open-sse/services/sessionManager.ts similarity index 99% rename from open-sse/services/sessionManager.js rename to open-sse/services/sessionManager.ts index 11ffd11be3..30ada6e85b 100644 --- a/open-sse/services/sessionManager.js +++ b/open-sse/services/sessionManager.ts @@ -43,6 +43,7 @@ export function generateSessionId(body, options = {}) { if (body.model) parts.push(`model:${body.model}`); // Provider binding + // @ts-ignore if (options.provider) parts.push(`provider:${options.provider}`); // System prompt hash (first 32 chars of system content) @@ -68,6 +69,7 @@ export function generateSessionId(body, options = {}) { } // Connection ID for sticky routing + // @ts-ignore if (options.connectionId) parts.push(`conn:${options.connectionId}`); if (parts.length === 0) return null; diff --git a/open-sse/services/signatureCache.js b/open-sse/services/signatureCache.ts similarity index 97% rename from open-sse/services/signatureCache.js rename to open-sse/services/signatureCache.ts index 82b810bb26..04f93c3c61 100644 --- a/open-sse/services/signatureCache.js +++ b/open-sse/services/signatureCache.ts @@ -38,17 +38,23 @@ export function getSignatures(context = {}) { const patterns = new Set(DEFAULT_SIGNATURES); // Layer 1: Tool (e.g., "cursor", "cline", "antigravity") + // @ts-ignore if (context.tool && layers.tool.has(context.tool)) { + // @ts-ignore for (const p of layers.tool.get(context.tool)) patterns.add(p); } // Layer 2: Model family (e.g., "claude-sonnet", "claude-opus") + // @ts-ignore if (context.modelFamily && layers.family.has(context.modelFamily)) { + // @ts-ignore for (const p of layers.family.get(context.modelFamily)) patterns.add(p); } // Layer 3: Session-specific + // @ts-ignore if (context.sessionId && layers.session.has(context.sessionId)) { + // @ts-ignore for (const p of layers.session.get(context.sessionId)) patterns.add(p); } @@ -80,8 +86,11 @@ export function addSignature(pattern, context = {}) { } }; + // @ts-ignore addToLayer(layers.tool, context.tool); + // @ts-ignore addToLayer(layers.family, context.modelFamily); + // @ts-ignore addToLayer(layers.session, context.sessionId); } diff --git a/open-sse/services/systemPrompt.js b/open-sse/services/systemPrompt.ts similarity index 100% rename from open-sse/services/systemPrompt.js rename to open-sse/services/systemPrompt.ts diff --git a/open-sse/services/thinkingBudget.js b/open-sse/services/thinkingBudget.ts similarity index 100% rename from open-sse/services/thinkingBudget.js rename to open-sse/services/thinkingBudget.ts diff --git a/open-sse/services/tokenRefresh.js b/open-sse/services/tokenRefresh.ts similarity index 100% rename from open-sse/services/tokenRefresh.js rename to open-sse/services/tokenRefresh.ts diff --git a/open-sse/services/usage.js b/open-sse/services/usage.ts similarity index 99% rename from open-sse/services/usage.js rename to open-sse/services/usage.ts index 185dd9918d..dc0b40e567 100644 --- a/open-sse/services/usage.js +++ b/open-sse/services/usage.ts @@ -38,7 +38,7 @@ const CLAUDE_CONFIG = { /** * Get usage data for a provider connection * @param {Object} connection - Provider connection with accessToken - * @returns {Object} Usage data with quotas + * @returns {Promise} Usage data with quotas */ export async function getUsageForProvider(connection) { const { provider, accessToken, providerSpecificData } = connection; @@ -49,6 +49,7 @@ export async function getUsageForProvider(connection) { case "gemini-cli": return await getGeminiUsage(accessToken); case "antigravity": + // @ts-ignore return await getAntigravityUsage(accessToken); case "claude": return await getClaudeUsage(accessToken); @@ -330,15 +331,18 @@ async function getAntigravityUsage(accessToken, providerSpecificData) { for (const [modelKey, info] of Object.entries(data.models)) { // Skip models without quota info + // @ts-ignore if (!info.quotaInfo) { continue; } // Skip internal models and non-important models + // @ts-ignore if (info.isInternal || !importantModels.includes(modelKey)) { continue; } + // @ts-ignore const remainingFraction = info.quotaInfo.remainingFraction || 0; const remainingPercentage = remainingFraction * 100; @@ -354,9 +358,11 @@ async function getAntigravityUsage(accessToken, providerSpecificData) { quotas[modelKey] = { used, total, + // @ts-ignore resetAt: parseResetTime(info.quotaInfo.resetTime), remainingPercentage, unlimited: false, + // @ts-ignore displayName: info.displayName || modelKey, }; } diff --git a/open-sse/services/wildcardRouter.js b/open-sse/services/wildcardRouter.ts similarity index 100% rename from open-sse/services/wildcardRouter.js rename to open-sse/services/wildcardRouter.ts diff --git a/open-sse/transformer/responsesTransformer.js b/open-sse/transformer/responsesTransformer.ts similarity index 98% rename from open-sse/transformer/responsesTransformer.js rename to open-sse/transformer/responsesTransformer.ts index e1c4318c20..fecaf7d250 100644 --- a/open-sse/transformer/responsesTransformer.js +++ b/open-sse/transformer/responsesTransformer.ts @@ -31,6 +31,7 @@ async function getPath() { // Create log directory for responses (Node.js only) export function createResponsesLogger(model, logsDir = null) { // Skip logging in worker environment (no fs) + // @ts-ignore - fs is available as a Node.js global or dynamically imported if (typeof fs.mkdirSync !== "function") { return null; } @@ -38,9 +39,11 @@ export function createResponsesLogger(model, logsDir = null) { const timestamp = new Date().toISOString().replace(/[:.]/g, "").slice(0, 15); const uniqueId = Math.random().toString(36).slice(2, 8); const baseDir = logsDir || (typeof process !== "undefined" ? process.cwd() : "."); + // @ts-ignore - path is available as a Node.js global const logDir = path.join(baseDir, "logs", `responses_${model}_${timestamp}_${uniqueId}`); try { + // @ts-ignore fs.mkdirSync(logDir, { recursive: true }); } catch { return null; @@ -58,7 +61,9 @@ export function createResponsesLogger(model, logsDir = null) { }, flush: () => { try { + // @ts-ignore fs.writeFileSync(path.join(logDir, "1_input_stream.txt"), inputEvents.join("\n")); + // @ts-ignore fs.writeFileSync(path.join(logDir, "2_output_stream.txt"), outputEvents.join("\n")); } catch (e) { console.log("[RESPONSES] Failed to write logs:", e.message); diff --git a/open-sse/translator/formats.js b/open-sse/translator/formats.ts similarity index 100% rename from open-sse/translator/formats.js rename to open-sse/translator/formats.ts diff --git a/open-sse/translator/helpers/claudeHelper.js b/open-sse/translator/helpers/claudeHelper.ts similarity index 100% rename from open-sse/translator/helpers/claudeHelper.js rename to open-sse/translator/helpers/claudeHelper.ts diff --git a/open-sse/translator/helpers/geminiHelper.js b/open-sse/translator/helpers/geminiHelper.ts similarity index 98% rename from open-sse/translator/helpers/geminiHelper.js rename to open-sse/translator/helpers/geminiHelper.ts index 0b9241152f..12b316ccb2 100644 --- a/open-sse/translator/helpers/geminiHelper.js +++ b/open-sse/translator/helpers/geminiHelper.ts @@ -197,13 +197,18 @@ function mergeAllOf(obj) { for (const item of obj.allOf) { if (item.properties) { + // @ts-ignore if (!merged.properties) merged.properties = {}; + // @ts-ignore Object.assign(merged.properties, item.properties); } if (item.required && Array.isArray(item.required)) { + // @ts-ignore if (!merged.required) merged.required = []; for (const req of item.required) { + // @ts-ignore if (!merged.required.includes(req)) { + // @ts-ignore merged.required.push(req); } } @@ -211,7 +216,9 @@ function mergeAllOf(obj) { } delete obj.allOf; + // @ts-ignore if (merged.properties) obj.properties = { ...obj.properties, ...merged.properties }; + // @ts-ignore if (merged.required) obj.required = [...(obj.required || []), ...merged.required]; } diff --git a/open-sse/translator/helpers/maxTokensHelper.js b/open-sse/translator/helpers/maxTokensHelper.ts similarity index 100% rename from open-sse/translator/helpers/maxTokensHelper.js rename to open-sse/translator/helpers/maxTokensHelper.ts diff --git a/open-sse/translator/helpers/openaiHelper.js b/open-sse/translator/helpers/openaiHelper.ts similarity index 100% rename from open-sse/translator/helpers/openaiHelper.js rename to open-sse/translator/helpers/openaiHelper.ts diff --git a/open-sse/translator/helpers/responsesApiHelper.js b/open-sse/translator/helpers/responsesApiHelper.ts similarity index 100% rename from open-sse/translator/helpers/responsesApiHelper.js rename to open-sse/translator/helpers/responsesApiHelper.ts diff --git a/open-sse/translator/helpers/toolCallHelper.js b/open-sse/translator/helpers/toolCallHelper.ts similarity index 100% rename from open-sse/translator/helpers/toolCallHelper.js rename to open-sse/translator/helpers/toolCallHelper.ts diff --git a/open-sse/translator/index.js b/open-sse/translator/index.ts similarity index 99% rename from open-sse/translator/index.js rename to open-sse/translator/index.ts index 3215da0ce9..e1e0b7a778 100644 --- a/open-sse/translator/index.js +++ b/open-sse/translator/index.ts @@ -234,6 +234,7 @@ export function translateResponse(targetFormat, sourceFormat, chunk, state) { // Attach OpenAI intermediate results for logging if (openaiResults && sourceFormat !== FORMATS.OPENAI && targetFormat !== FORMATS.OPENAI) { + // @ts-ignore — custom expando property for logging results._openaiIntermediate = openaiResults; } diff --git a/open-sse/translator/request/antigravity-to-openai.js b/open-sse/translator/request/antigravity-to-openai.ts similarity index 95% rename from open-sse/translator/request/antigravity-to-openai.js rename to open-sse/translator/request/antigravity-to-openai.ts index 4a6402d17e..9e5240edd8 100644 --- a/open-sse/translator/request/antigravity-to-openai.js +++ b/open-sse/translator/request/antigravity-to-openai.ts @@ -17,15 +17,19 @@ export function antigravityToOpenAIRequest(model, body, stream) { const config = req.generationConfig; if (config.maxOutputTokens) { const tempBody = { max_tokens: config.maxOutputTokens, tools: req.tools }; + // @ts-ignore result.max_tokens = adjustMaxTokens(tempBody); } if (config.temperature !== undefined) { + // @ts-ignore result.temperature = config.temperature; } if (config.topP !== undefined) { + // @ts-ignore result.top_p = config.topP; } if (config.topK !== undefined) { + // @ts-ignore result.top_k = config.topK; } @@ -34,10 +38,13 @@ export function antigravityToOpenAIRequest(model, body, stream) { const budget = config.thinkingConfig.thinkingBudget || 0; if (budget > 0) { if (budget <= 2048) { + // @ts-ignore result.reasoning_effort = "low"; } else if (budget <= 16384) { + // @ts-ignore result.reasoning_effort = "medium"; } else { + // @ts-ignore result.reasoning_effort = "high"; } } @@ -68,10 +75,12 @@ export function antigravityToOpenAIRequest(model, body, stream) { // Tools if (req.tools && Array.isArray(req.tools)) { + // @ts-ignore result.tools = []; for (const tool of req.tools) { if (tool.functionDeclarations) { for (const func of tool.functionDeclarations) { + // @ts-ignore result.tools.push({ type: "function", function: { @@ -192,12 +201,15 @@ function convertContent(content) { if (toolCalls.length > 0) { const msg = { role: "assistant" }; if (textParts.length > 0) { + // @ts-ignore msg.content = textParts.length === 1 && textParts[0].type === "text" ? textParts[0].text : textParts; } if (reasoningContent) { + // @ts-ignore msg.reasoning_content = reasoningContent; } + // @ts-ignore msg.tool_calls = toolCalls; return msg; } @@ -206,10 +218,12 @@ function convertContent(content) { if (textParts.length > 0 || reasoningContent) { const msg = { role }; if (textParts.length > 0) { + // @ts-ignore msg.content = textParts.length === 1 && textParts[0].type === "text" ? textParts[0].text : textParts; } if (reasoningContent) { + // @ts-ignore msg.reasoning_content = reasoningContent; } return msg; diff --git a/open-sse/translator/request/claude-to-gemini.js b/open-sse/translator/request/claude-to-gemini.ts similarity index 97% rename from open-sse/translator/request/claude-to-gemini.js rename to open-sse/translator/request/claude-to-gemini.ts index 3b5c7f21ba..a75d6053a8 100644 --- a/open-sse/translator/request/claude-to-gemini.js +++ b/open-sse/translator/request/claude-to-gemini.ts @@ -18,15 +18,19 @@ export function claudeToGeminiRequest(model, body, stream) { // ── Generation config ────────────────────────────────────────── if (body.temperature !== undefined) { + // @ts-ignore result.generationConfig.temperature = body.temperature; } if (body.top_p !== undefined) { + // @ts-ignore result.generationConfig.topP = body.top_p; } if (body.top_k !== undefined) { + // @ts-ignore result.generationConfig.topK = body.top_k; } if (body.max_tokens !== undefined) { + // @ts-ignore result.generationConfig.maxOutputTokens = body.max_tokens; } @@ -39,6 +43,7 @@ export function claudeToGeminiRequest(model, body, stream) { systemText = String(body.system); } if (systemText) { + // @ts-ignore result.systemInstruction = { role: "user", parts: [{ text: systemText }], @@ -152,12 +157,14 @@ export function claudeToGeminiRequest(model, body, stream) { } } if (functionDeclarations.length > 0) { + // @ts-ignore result.tools = [{ functionDeclarations }]; } } // ── Thinking config ──────────────────────────────────────────── if (body.thinking?.type === "enabled" && body.thinking.budget_tokens) { + // @ts-ignore result.generationConfig.thinkingConfig = { thinkingBudget: body.thinking.budget_tokens, include_thoughts: true, diff --git a/open-sse/translator/request/claude-to-openai.js b/open-sse/translator/request/claude-to-openai.ts similarity index 98% rename from open-sse/translator/request/claude-to-openai.js rename to open-sse/translator/request/claude-to-openai.ts index 040b54d2ae..2fb77293b8 100644 --- a/open-sse/translator/request/claude-to-openai.js +++ b/open-sse/translator/request/claude-to-openai.ts @@ -12,11 +12,13 @@ export function claudeToOpenAIRequest(model, body, stream) { // Max tokens if (body.max_tokens) { + // @ts-ignore result.max_tokens = adjustMaxTokens(body); } // Temperature if (body.temperature !== undefined) { + // @ts-ignore result.temperature = body.temperature; } @@ -55,6 +57,7 @@ export function claudeToOpenAIRequest(model, body, stream) { // Tools if (body.tools && Array.isArray(body.tools)) { + // @ts-ignore result.tools = body.tools.map((tool) => ({ type: "function", function: { @@ -67,6 +70,7 @@ export function claudeToOpenAIRequest(model, body, stream) { // Tool choice if (body.tool_choice) { + // @ts-ignore result.tool_choice = convertToolChoice(body.tool_choice); } @@ -188,8 +192,10 @@ function convertClaudeMessage(msg) { if (toolCalls.length > 0) { const result = { role: "assistant" }; if (parts.length > 0) { + // @ts-ignore result.content = parts.length === 1 && parts[0].type === "text" ? parts[0].text : parts; } + // @ts-ignore result.tool_calls = toolCalls; return result; } diff --git a/open-sse/translator/request/gemini-to-openai.js b/open-sse/translator/request/gemini-to-openai.ts similarity index 96% rename from open-sse/translator/request/gemini-to-openai.js rename to open-sse/translator/request/gemini-to-openai.ts index ad067e070e..c7a745cdd5 100644 --- a/open-sse/translator/request/gemini-to-openai.js +++ b/open-sse/translator/request/gemini-to-openai.ts @@ -15,12 +15,15 @@ export function geminiToOpenAIRequest(model, body, stream) { const config = body.generationConfig; if (config.maxOutputTokens) { const tempBody = { max_tokens: config.maxOutputTokens, tools: body.tools }; + // @ts-ignore result.max_tokens = adjustMaxTokens(tempBody); } if (config.temperature !== undefined) { + // @ts-ignore result.temperature = config.temperature; } if (config.topP !== undefined) { + // @ts-ignore result.top_p = config.topP; } } @@ -48,10 +51,12 @@ export function geminiToOpenAIRequest(model, body, stream) { // Tools if (body.tools && Array.isArray(body.tools)) { + // @ts-ignore result.tools = []; for (const tool of body.tools) { if (tool.functionDeclarations) { for (const func of tool.functionDeclarations) { + // @ts-ignore result.tools.push({ type: "function", function: { @@ -118,8 +123,10 @@ function convertGeminiContent(content) { if (toolCalls.length > 0) { const result = { role: "assistant" }; if (parts.length > 0) { + // @ts-ignore result.content = parts.length === 1 ? parts[0].text : parts; } + // @ts-ignore result.tool_calls = toolCalls; return result; } diff --git a/open-sse/translator/request/openai-responses.js b/open-sse/translator/request/openai-responses.ts similarity index 97% rename from open-sse/translator/request/openai-responses.js rename to open-sse/translator/request/openai-responses.ts index c3176ee2d4..bef28d0b2a 100644 --- a/open-sse/translator/request/openai-responses.js +++ b/open-sse/translator/request/openai-responses.ts @@ -21,7 +21,9 @@ export function openaiResponsesToOpenAIRequest(model, body, stream, credentials) const error = new Error( `Unsupported Responses API feature: ${tool.type} tool type is not supported by omniroute` ); + // @ts-ignore — custom error property error.statusCode = 400; + // @ts-ignore — custom error property error.errorType = "unsupported_feature"; throw error; } @@ -31,7 +33,9 @@ export function openaiResponsesToOpenAIRequest(model, body, stream, credentials) const error = new Error( "Unsupported Responses API feature: background mode is not supported by omniroute" ); + // @ts-ignore — custom error property error.statusCode = 400; + // @ts-ignore — custom error property error.errorType = "unsupported_feature"; throw error; } @@ -174,6 +178,7 @@ export function openaiToOpenAIResponsesRequest(model, body, stream, credentials) if (msg.role === "system") { // Use first system message as instructions if (!hasSystemMessage) { + // @ts-ignore result.instructions = typeof msg.content === "string" ? msg.content : ""; hasSystemMessage = true; } @@ -275,11 +280,13 @@ export function openaiToOpenAIResponsesRequest(model, body, stream, credentials) // If no system message, leave instructions empty if (!hasSystemMessage) { + // @ts-ignore result.instructions = ""; } // Convert tools format if (body.tools && Array.isArray(body.tools)) { + // @ts-ignore result.tools = body.tools.map((tool) => { if (tool.type === "function") { return { @@ -295,8 +302,11 @@ export function openaiToOpenAIResponsesRequest(model, body, stream, credentials) } // Pass through other relevant fields + // @ts-ignore if (body.temperature !== undefined) result.temperature = body.temperature; + // @ts-ignore if (body.max_tokens !== undefined) result.max_tokens = body.max_tokens; + // @ts-ignore if (body.top_p !== undefined) result.top_p = body.top_p; return result; diff --git a/open-sse/translator/request/openai-to-claude.js b/open-sse/translator/request/openai-to-claude.ts similarity index 96% rename from open-sse/translator/request/openai-to-claude.js rename to open-sse/translator/request/openai-to-claude.ts index 5a2ccb3b0a..c07759e173 100644 --- a/open-sse/translator/request/openai-to-claude.js +++ b/open-sse/translator/request/openai-to-claude.ts @@ -19,10 +19,12 @@ export function openaiToClaudeRequest(model, body, stream) { // Temperature if (body.temperature !== undefined) { + // @ts-ignore result.temperature = body.temperature; } // Messages + // @ts-ignore result.messages = []; const systemParts = []; @@ -46,6 +48,7 @@ export function openaiToClaudeRequest(model, body, stream) { const flushCurrentMessage = () => { if (currentRole && currentParts.length > 0) { + // @ts-ignore result.messages.push({ role: currentRole, content: currentParts }); currentParts = []; } @@ -65,6 +68,7 @@ export function openaiToClaudeRequest(model, body, stream) { flushCurrentMessage(); if (toolResultBlocks.length > 0) { + // @ts-ignore result.messages.push({ role: "user", content: toolResultBlocks }); } @@ -90,7 +94,9 @@ export function openaiToClaudeRequest(model, body, stream) { flushCurrentMessage(); // Add cache_control to last assistant message + // @ts-ignore for (let i = result.messages.length - 1; i >= 0; i--) { + // @ts-ignore const message = result.messages[i]; if ( message.role === "assistant" && @@ -111,16 +117,19 @@ export function openaiToClaudeRequest(model, body, stream) { if (systemParts.length > 0) { const systemText = systemParts.join("\n"); + // @ts-ignore result.system = [ claudeCodePrompt, { type: "text", text: systemText, cache_control: { type: "ephemeral", ttl: "1h" } }, ]; } else { + // @ts-ignore result.system = [claudeCodePrompt]; } // Tools - convert from OpenAI format to Claude format with prefix for OAuth if (body.tools && Array.isArray(body.tools)) { + // @ts-ignore result.tools = body.tools.map((tool) => { const toolData = tool.type === "function" && tool.function ? tool.function : tool; const originalName = toolData.name; @@ -139,18 +148,22 @@ export function openaiToClaudeRequest(model, body, stream) { }; }); + // @ts-ignore if (result.tools.length > 0) { + // @ts-ignore result.tools[result.tools.length - 1].cache_control = { type: "ephemeral", ttl: "1h" }; } } // Tool choice if (body.tool_choice) { + // @ts-ignore result.tool_choice = convertOpenAIToolChoice(body.tool_choice); } // Thinking configuration if (body.thinking) { + // @ts-ignore result.thinking = { type: body.thinking.type || "enabled", ...(body.thinking.budget_tokens && { budget_tokens: body.thinking.budget_tokens }), @@ -160,6 +173,7 @@ export function openaiToClaudeRequest(model, body, stream) { // Attach toolNameMap to result for response translation if (toolNameMap.size > 0) { + // @ts-ignore result._toolNameMap = toolNameMap; } @@ -296,17 +310,23 @@ function openaiToClaudeRequestForAntigravity(model, body, stream) { const result = openaiToClaudeRequest(model, body, stream); // Remove Claude Code system prompt, keep only user's system messages + // @ts-ignore if (result.system && Array.isArray(result.system)) { + // @ts-ignore result.system = result.system.filter( (block) => !block.text || !block.text.includes("You are Claude Code") ); + // @ts-ignore if (result.system.length === 0) { + // @ts-ignore delete result.system; } } // Strip prefix from tool names for Antigravity (doesn't use Claude OAuth) + // @ts-ignore if (result.tools && Array.isArray(result.tools)) { + // @ts-ignore result.tools = result.tools.map((tool) => { if (tool.name && tool.name.startsWith(CLAUDE_OAUTH_TOOL_PREFIX)) { return { @@ -319,7 +339,9 @@ function openaiToClaudeRequestForAntigravity(model, body, stream) { } // Strip prefix from tool_use in messages + // @ts-ignore if (result.messages && Array.isArray(result.messages)) { + // @ts-ignore result.messages = result.messages.map((msg) => { if (!msg.content || !Array.isArray(msg.content)) { return msg; diff --git a/open-sse/translator/request/openai-to-cursor.js b/open-sse/translator/request/openai-to-cursor.ts similarity index 97% rename from open-sse/translator/request/openai-to-cursor.js rename to open-sse/translator/request/openai-to-cursor.ts index e8e7485dfc..36303bccf9 100644 --- a/open-sse/translator/request/openai-to-cursor.js +++ b/open-sse/translator/request/openai-to-cursor.ts @@ -68,12 +68,15 @@ function convertMessages(messages) { if (msg.role === "assistant" && msg.tool_calls && msg.tool_calls.length > 0) { const assistantMsg = { role: "assistant" }; if (content) { + // @ts-ignore assistantMsg.content = content; } + // @ts-ignore assistantMsg.tool_calls = msg.tool_calls; // Attach pending tool results to assistant message with tool_calls if (pendingToolResults.length > 0) { + // @ts-ignore assistantMsg.tool_results = pendingToolResults; pendingToolResults = []; } @@ -87,6 +90,7 @@ function convertMessages(messages) { // Attach pending tool results to this message if (pendingToolResults.length > 0) { + // @ts-ignore msgObj.tool_results = pendingToolResults; pendingToolResults = []; } diff --git a/open-sse/translator/request/openai-to-gemini.js b/open-sse/translator/request/openai-to-gemini.ts similarity index 97% rename from open-sse/translator/request/openai-to-gemini.js rename to open-sse/translator/request/openai-to-gemini.ts index 3945852499..4c3d2e6c1c 100644 --- a/open-sse/translator/request/openai-to-gemini.js +++ b/open-sse/translator/request/openai-to-gemini.ts @@ -30,15 +30,19 @@ function openaiToGeminiBase(model, body, stream) { // Generation config if (body.temperature !== undefined) { + // @ts-ignore result.generationConfig.temperature = body.temperature; } if (body.top_p !== undefined) { + // @ts-ignore result.generationConfig.topP = body.top_p; } if (body.top_k !== undefined) { + // @ts-ignore result.generationConfig.topK = body.top_k; } if (body.max_tokens !== undefined) { + // @ts-ignore result.generationConfig.maxOutputTokens = body.max_tokens; } @@ -74,6 +78,7 @@ function openaiToGeminiBase(model, body, stream) { const content = msg.content; if (role === "system" && body.messages.length > 1) { + // @ts-ignore result.systemInstruction = { role: "user", parts: [{ text: typeof content === "string" ? content : extractTextContent(content) }], @@ -195,6 +200,7 @@ function openaiToGeminiBase(model, body, stream) { } if (functionDeclarations.length > 0) { + // @ts-ignore result.tools = [{ functionDeclarations }]; } } @@ -216,6 +222,7 @@ export function openaiToGeminiCLIRequest(model, body, stream) { if (body.reasoning_effort) { const budgetMap = { low: 1024, medium: 8192, high: 32768 }; const budget = budgetMap[body.reasoning_effort] || 8192; + // @ts-ignore gemini.generationConfig.thinkingConfig = { thinkingBudget: budget, include_thoughts: true, @@ -224,6 +231,7 @@ export function openaiToGeminiCLIRequest(model, body, stream) { // Thinking config from Claude format if (body.thinking?.type === "enabled" && body.thinking.budget_tokens) { + // @ts-ignore gemini.generationConfig.thinkingConfig = { thinkingBudget: body.thinking.budget_tokens, include_thoughts: true, @@ -231,7 +239,9 @@ export function openaiToGeminiCLIRequest(model, body, stream) { } // Clean schema for tools + // @ts-ignore if (gemini.tools?.[0]?.functionDeclarations) { + // @ts-ignore for (const fn of gemini.tools[0].functionDeclarations) { if (fn.parameters) { const cleanedSchema = cleanJSONSchemaForAntigravity(fn.parameters); @@ -269,6 +279,7 @@ function wrapInCloudCodeEnvelope(model, geminiCLI, credentials = null, isAntigra // Antigravity specific fields if (isAntigravity) { + // @ts-ignore envelope.requestType = "agent"; // Inject required default system prompt for Antigravity @@ -281,12 +292,14 @@ function wrapInCloudCodeEnvelope(model, geminiCLI, credentials = null, isAntigra // Add toolConfig for Antigravity if (geminiCLI.tools?.length > 0) { + // @ts-ignore envelope.request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" }, }; } } else { // Keep safetySettings for Gemini CLI + // @ts-ignore envelope.request.safetySettings = geminiCLI.safetySettings; } @@ -373,7 +386,9 @@ function wrapInCloudCodeEnvelopeForClaude(model, claudeRequest, credentials = nu } } if (functionDeclarations.length > 0) { + // @ts-ignore envelope.request.tools = [{ functionDeclarations }]; + // @ts-ignore envelope.request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" }, }; @@ -394,6 +409,7 @@ function wrapInCloudCodeEnvelopeForClaude(model, claudeRequest, credentials = nu } } + // @ts-ignore envelope.request.systemInstruction = { role: "user", parts: systemParts }; return envelope; diff --git a/open-sse/translator/request/openai-to-kiro.js b/open-sse/translator/request/openai-to-kiro.ts similarity index 98% rename from open-sse/translator/request/openai-to-kiro.js rename to open-sse/translator/request/openai-to-kiro.ts index 8529b2cf3f..866bfd85f9 100644 --- a/open-sse/translator/request/openai-to-kiro.js +++ b/open-sse/translator/request/openai-to-kiro.ts @@ -30,6 +30,7 @@ function convertMessages(messages, tools, model) { }; if (pendingToolResults.length > 0) { + // @ts-ignore userMsg.userInputMessage.userInputMessageContext = { toolResults: pendingToolResults, }; @@ -37,9 +38,12 @@ function convertMessages(messages, tools, model) { // Add tools to first user message if (tools && tools.length > 0 && history.length === 0) { + // @ts-ignore if (!userMsg.userInputMessage.userInputMessageContext) { + // @ts-ignore userMsg.userInputMessage.userInputMessageContext = {}; } + // @ts-ignore userMsg.userInputMessage.userInputMessageContext.tools = tools.map((t) => { const name = t.function?.name || t.name; let description = t.function?.description || t.description || ""; @@ -274,13 +278,18 @@ export function buildKiroPayload(model, body, stream, credentials) { }; if (profileArn) { + // @ts-ignore payload.profileArn = profileArn; } if (maxTokens || temperature !== undefined || topP !== undefined) { + // @ts-ignore payload.inferenceConfig = {}; + // @ts-ignore if (maxTokens) payload.inferenceConfig.maxTokens = maxTokens; + // @ts-ignore if (temperature !== undefined) payload.inferenceConfig.temperature = temperature; + // @ts-ignore if (topP !== undefined) payload.inferenceConfig.topP = topP; } diff --git a/open-sse/translator/response/claude-to-openai.js b/open-sse/translator/response/claude-to-openai.ts similarity index 98% rename from open-sse/translator/response/claude-to-openai.js rename to open-sse/translator/response/claude-to-openai.ts index 57e5f9f9b9..94adfb4a9a 100644 --- a/open-sse/translator/response/claude-to-openai.js +++ b/open-sse/translator/response/claude-to-openai.ts @@ -161,6 +161,7 @@ export function claudeToOpenAIResponse(chunk, state) { const completionTokens = outputTokens; const totalTokens = promptTokens + completionTokens; + // @ts-ignore finalChunk.usage = { prompt_tokens: promptTokens, completion_tokens: completionTokens, @@ -169,11 +170,14 @@ export function claudeToOpenAIResponse(chunk, state) { // Add prompt_tokens_details if cached tokens exist if (cachedTokens > 0 || cacheCreationTokens > 0) { + // @ts-ignore finalChunk.usage.prompt_tokens_details = {}; if (cachedTokens > 0) { + // @ts-ignore finalChunk.usage.prompt_tokens_details.cached_tokens = cachedTokens; } if (cacheCreationTokens > 0) { + // @ts-ignore finalChunk.usage.prompt_tokens_details.cache_creation_tokens = cacheCreationTokens; } } diff --git a/open-sse/translator/response/cursor-to-openai.js b/open-sse/translator/response/cursor-to-openai.ts similarity index 100% rename from open-sse/translator/response/cursor-to-openai.js rename to open-sse/translator/response/cursor-to-openai.ts diff --git a/open-sse/translator/response/gemini-to-claude.js b/open-sse/translator/response/gemini-to-claude.ts similarity index 100% rename from open-sse/translator/response/gemini-to-claude.js rename to open-sse/translator/response/gemini-to-claude.ts diff --git a/open-sse/translator/response/gemini-to-openai.js b/open-sse/translator/response/gemini-to-openai.ts similarity index 99% rename from open-sse/translator/response/gemini-to-openai.js rename to open-sse/translator/response/gemini-to-openai.ts index a678618b8d..b09dfef4b8 100644 --- a/open-sse/translator/response/gemini-to-openai.js +++ b/open-sse/translator/response/gemini-to-openai.ts @@ -242,6 +242,7 @@ export function geminiToOpenAIResponse(chunk, state) { // Include usage in final chunk for downstream translators if (state.usage) { + // @ts-ignore finalChunk.usage = state.usage; } diff --git a/open-sse/translator/response/kiro-to-openai.js b/open-sse/translator/response/kiro-to-openai.ts similarity index 99% rename from open-sse/translator/response/kiro-to-openai.js rename to open-sse/translator/response/kiro-to-openai.ts index 5e9e8a840d..9541035002 100644 --- a/open-sse/translator/response/kiro-to-openai.js +++ b/open-sse/translator/response/kiro-to-openai.ts @@ -171,6 +171,7 @@ export function convertKiroToOpenAI(chunk, state) { // Include usage in final chunk if available if (state.usage && typeof state.usage === "object") { + // @ts-ignore openaiChunk.usage = state.usage; } diff --git a/open-sse/translator/response/openai-responses.js b/open-sse/translator/response/openai-responses.ts similarity index 99% rename from open-sse/translator/response/openai-responses.js rename to open-sse/translator/response/openai-responses.ts index bd4efa4a0e..2aa4dbe716 100644 --- a/open-sse/translator/response/openai-responses.js +++ b/open-sse/translator/response/openai-responses.ts @@ -535,6 +535,7 @@ export function openaiResponsesToOpenAIResponse(chunk, state) { // Include usage in final chunk if available if (state.usage && typeof state.usage === "object") { + // @ts-ignore finalChunk.usage = state.usage; } diff --git a/open-sse/translator/response/openai-to-antigravity.js b/open-sse/translator/response/openai-to-antigravity.ts similarity index 98% rename from open-sse/translator/response/openai-to-antigravity.js rename to open-sse/translator/response/openai-to-antigravity.ts index 30bee0ac54..70cc673ca2 100644 --- a/open-sse/translator/response/openai-to-antigravity.js +++ b/open-sse/translator/response/openai-to-antigravity.ts @@ -91,6 +91,7 @@ export function openaiToAntigravityResponse(chunk, state) { tool_calls: "STOP", content_filter: "SAFETY", }; + // @ts-ignore candidate.finishReason = reasonMap[finishReason] || "STOP"; } @@ -104,15 +105,18 @@ export function openaiToAntigravityResponse(chunk, state) { // Usage metadata const usage = chunk.usage || state._usage; if (usage) { + // @ts-ignore response.usageMetadata = { promptTokenCount: usage.prompt_tokens || 0, candidatesTokenCount: usage.completion_tokens || 0, totalTokenCount: usage.total_tokens || 0, }; if (usage.completion_tokens_details?.reasoning_tokens) { + // @ts-ignore response.usageMetadata.thoughtsTokenCount = usage.completion_tokens_details.reasoning_tokens; } if (usage.prompt_tokens_details?.cached_tokens) { + // @ts-ignore response.usageMetadata.cachedContentTokenCount = usage.prompt_tokens_details.cached_tokens; } } diff --git a/open-sse/translator/response/openai-to-claude.js b/open-sse/translator/response/openai-to-claude.ts similarity index 100% rename from open-sse/translator/response/openai-to-claude.js rename to open-sse/translator/response/openai-to-claude.ts diff --git a/open-sse/tsconfig.json b/open-sse/tsconfig.json new file mode 100644 index 0000000000..bffe1dbf28 --- /dev/null +++ b/open-sse/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "esnext", + "moduleResolution": "bundler", + "allowJs": true, + "checkJs": true, + "noEmit": true, + "skipLibCheck": true, + "esModuleInterop": true, + "strict": false, + "jsx": "react-jsx", + "lib": ["dom", "esnext"], + "baseUrl": "..", + "paths": { + "@/*": ["./src/*"], + "@omniroute/open-sse": ["./open-sse"], + "@omniroute/open-sse/*": ["./open-sse/*"] + } + }, + "include": [ + "**/*.ts", + "**/*.js" + ] +} diff --git a/open-sse/utils/bypassHandler.js b/open-sse/utils/bypassHandler.ts similarity index 100% rename from open-sse/utils/bypassHandler.js rename to open-sse/utils/bypassHandler.ts diff --git a/open-sse/utils/cursorChecksum.js b/open-sse/utils/cursorChecksum.ts similarity index 100% rename from open-sse/utils/cursorChecksum.js rename to open-sse/utils/cursorChecksum.ts diff --git a/open-sse/utils/cursorProtobuf.js b/open-sse/utils/cursorProtobuf.ts similarity index 100% rename from open-sse/utils/cursorProtobuf.js rename to open-sse/utils/cursorProtobuf.ts diff --git a/open-sse/utils/error.js b/open-sse/utils/error.ts similarity index 95% rename from open-sse/utils/error.js rename to open-sse/utils/error.ts index 12888e057d..479cd288d4 100644 --- a/open-sse/utils/error.js +++ b/open-sse/utils/error.ts @@ -131,8 +131,8 @@ export async function parseUpstreamError(response, provider = null) { * @param {number|null} retryAfterMs - Optional retry-after time in milliseconds * @returns {{ success: false, status: number, error: string, response: Response, retryAfterMs?: number }} */ -export function createErrorResult(statusCode, message, retryAfterMs = null) { - const result = { +export function createErrorResult(statusCode: number, message: string, retryAfterMs: number | null = null) { + const result: Record = { success: false, status: statusCode, error: message, @@ -144,6 +144,7 @@ export function createErrorResult(statusCode, message, retryAfterMs = null) { result.retryAfterMs = retryAfterMs; } + // @ts-ignore - boolean is assignable to false at runtime return result; } @@ -179,6 +180,7 @@ export function unavailableResponse(statusCode, message, retryAfter, retryAfterH * @returns {string} Formatted error message */ export function formatProviderError(error, provider, model, statusCode) { + // @ts-ignore - Error may have custom 'code' property const code = statusCode || error.code || "FETCH_FAILED"; const message = error.message || "Unknown error"; return `[${code}]: ${message}`; diff --git a/open-sse/utils/logger.js b/open-sse/utils/logger.ts similarity index 98% rename from open-sse/utils/logger.js rename to open-sse/utils/logger.ts index eca067b9f8..ab205c9c6b 100644 --- a/open-sse/utils/logger.js +++ b/open-sse/utils/logger.ts @@ -96,7 +96,7 @@ export function logger(tag) { const consoleFn = getConsoleFn(level); if (jsonFormat) { - const entry = { + const entry: Record = { ts: new Date().toISOString(), level, tag, @@ -132,7 +132,7 @@ export function createLogger(requestId = null) { const consoleFn = getConsoleFn(level); if (jsonFormat) { - const entry = { + const entry: Record = { ts: new Date().toISOString(), level, tag, diff --git a/open-sse/utils/networkProxy.js b/open-sse/utils/networkProxy.ts similarity index 98% rename from open-sse/utils/networkProxy.js rename to open-sse/utils/networkProxy.ts index 9fbc3ea28e..b0c4e33058 100644 --- a/open-sse/utils/networkProxy.js +++ b/open-sse/utils/networkProxy.ts @@ -34,6 +34,7 @@ async function getConfig() { * @param {string} providerId - Provider ID (e.g., "openai", "anthropic") * @returns {string|null} Proxy URL or null if no proxy configured */ +/** @returns {Promise} */ export async function resolveProxy(providerId) { const config = await getConfig(); diff --git a/open-sse/utils/ollamaTransform.js b/open-sse/utils/ollamaTransform.ts similarity index 96% rename from open-sse/utils/ollamaTransform.js rename to open-sse/utils/ollamaTransform.ts index 6f1c788ec9..a993d081af 100644 --- a/open-sse/utils/ollamaTransform.js +++ b/open-sse/utils/ollamaTransform.ts @@ -1,7 +1,7 @@ // Transform OpenAI SSE stream to Ollama JSON lines format export function transformToOllama(response, model) { let buffer = ""; - let pendingToolCalls = {}; + let pendingToolCalls: Record = {}; const transform = new TransformStream({ transform(chunk, controller) { @@ -51,7 +51,7 @@ export function transformToOllama(response, model) { if (finishReason === "tool_calls" || finishReason === "stop") { const toolCallsArr = Object.values(pendingToolCalls); if (toolCallsArr.length > 0) { - const formattedCalls = toolCallsArr.map((tc) => ({ + const formattedCalls = toolCallsArr.map((tc: any) => ({ function: { name: tc.function.name, arguments: JSON.parse(tc.function.arguments || "{}"), diff --git a/open-sse/utils/progressTracker.js b/open-sse/utils/progressTracker.ts similarity index 97% rename from open-sse/utils/progressTracker.js rename to open-sse/utils/progressTracker.ts index d42dcdd612..20845c390d 100644 --- a/open-sse/utils/progressTracker.js +++ b/open-sse/utils/progressTracker.ts @@ -21,7 +21,7 @@ const DEFAULT_INTERVAL_MS = 2000; * @param {AbortSignal} [options.signal] - Abort signal for cancellation * @returns {TransformStream} */ -export function createProgressTransform({ intervalMs = DEFAULT_INTERVAL_MS, signal } = {}) { +export function createProgressTransform({ intervalMs = DEFAULT_INTERVAL_MS, signal }: { intervalMs?: number; signal?: AbortSignal } = {}) { let tokenCount = 0; let startTime = Date.now(); let intervalId; diff --git a/open-sse/utils/proxyDispatcher.js b/open-sse/utils/proxyDispatcher.ts similarity index 97% rename from open-sse/utils/proxyDispatcher.js rename to open-sse/utils/proxyDispatcher.ts index 0a4f235e1c..c6c0ef70c1 100644 --- a/open-sse/utils/proxyDispatcher.js +++ b/open-sse/utils/proxyDispatcher.ts @@ -112,13 +112,14 @@ export function createProxyDispatcher(proxyUrl) { const parsed = new URL(normalizedUrl); if (parsed.protocol === "socks5:") { - const socksOptions = { + const socksOptions: Record = { type: 5, host: parsed.hostname, port: Number(normalizePort(parsed.port, parsed.protocol)), }; if (parsed.username) socksOptions.userId = decodeURIComponent(parsed.username); if (parsed.password) socksOptions.password = decodeURIComponent(parsed.password); + // @ts-ignore - socksOptions conforms to SocksProxies at runtime dispatcher = socksDispatcher(socksOptions); } else { dispatcher = new ProxyAgent(normalizedUrl); diff --git a/open-sse/utils/proxyFetch.js b/open-sse/utils/proxyFetch.ts similarity index 96% rename from open-sse/utils/proxyFetch.js rename to open-sse/utils/proxyFetch.ts index 92a62c7497..5bcce7a285 100644 --- a/open-sse/utils/proxyFetch.js +++ b/open-sse/utils/proxyFetch.ts @@ -126,7 +126,7 @@ export async function runWithProxyContext(proxyConfig, fn) { }); } -async function patchedFetch(input, options = {}) { +async function patchedFetch(input: any, options: any = {}) { if (options?.dispatcher) { return originalFetch(input, options); } @@ -146,7 +146,7 @@ async function patchedFetch(input, options = {}) { // TLS fingerprint spoofing for direct connections (no proxy configured) if (isTlsFingerprintEnabled() && tlsClient.available) { try { - const store = tlsFingerprintContext.getStore(); + const store: any = tlsFingerprintContext.getStore(); if (store) store.used = true; return await tlsClient.fetch(targetUrl, options); } catch (error) { @@ -154,7 +154,7 @@ async function patchedFetch(input, options = {}) { console.warn( `[ProxyFetch] TLS fingerprint failed, falling back to native fetch: ${message}` ); - const store = tlsFingerprintContext.getStore(); + const store: any = tlsFingerprintContext.getStore(); if (store) store.used = false; } } diff --git a/open-sse/utils/requestLogger.js b/open-sse/utils/requestLogger.ts similarity index 100% rename from open-sse/utils/requestLogger.js rename to open-sse/utils/requestLogger.ts diff --git a/open-sse/utils/stream.js b/open-sse/utils/stream.ts similarity index 97% rename from open-sse/utils/stream.js rename to open-sse/utils/stream.ts index c4e4d896a4..f4f7e8f61f 100644 --- a/open-sse/utils/stream.js +++ b/open-sse/utils/stream.ts @@ -44,13 +44,15 @@ const STREAM_MODE = { * @param {object} options.body - Request body (for input token estimation) * @param {function} options.onComplete - Callback when stream finishes: ({ status, usage }) => void */ -export function createSSEStream(options = {}) { +/** @param {any} options */ +export function createSSEStream(options: any = {}) { const { mode = STREAM_MODE.TRANSLATE, targetFormat, sourceFormat, provider = null, reqLogger = null, + /** @type {any} */ toolNameMap = null, model = null, connectionId = null, @@ -231,7 +233,9 @@ export function createSSEStream(options = {}) { const translated = translateResponse(targetFormat, sourceFormat, parsed, state); // Log OpenAI intermediate chunks (if available) + // @ts-ignore - _openaiIntermediate is a custom property on translated arrays if (translated?._openaiIntermediate) { + // @ts-ignore for (const item of translated._openaiIntermediate) { const openaiOutput = formatSSE(item, FORMATS.OPENAI); reqLogger?.appendOpenAIChunk?.(openaiOutput); @@ -327,7 +331,9 @@ export function createSSEStream(options = {}) { const translated = translateResponse(targetFormat, sourceFormat, parsed, state); // Log OpenAI intermediate chunks + // @ts-ignore - _openaiIntermediate is a custom property if (translated?._openaiIntermediate) { + // @ts-ignore for (const item of translated._openaiIntermediate) { const openaiOutput = formatSSE(item, FORMATS.OPENAI); reqLogger?.appendOpenAIChunk?.(openaiOutput); @@ -348,7 +354,9 @@ export function createSSEStream(options = {}) { const flushed = translateResponse(targetFormat, sourceFormat, null, state); // Log OpenAI intermediate chunks for flushed events + // @ts-ignore - _openaiIntermediate is a custom property if (flushed?._openaiIntermediate) { + // @ts-ignore for (const item of flushed._openaiIntermediate) { const openaiOutput = formatSSE(item, FORMATS.OPENAI); reqLogger?.appendOpenAIChunk?.(openaiOutput); @@ -434,6 +442,7 @@ export function createSSETransformStreamWithLogger( sourceFormat, provider, reqLogger, + // @ts-ignore toolNameMap, model, connectionId, diff --git a/open-sse/utils/streamHandler.js b/open-sse/utils/streamHandler.ts similarity index 98% rename from open-sse/utils/streamHandler.js rename to open-sse/utils/streamHandler.ts index 2f6bffe144..ff92aa5cbf 100644 --- a/open-sse/utils/streamHandler.js +++ b/open-sse/utils/streamHandler.ts @@ -18,7 +18,8 @@ function getTimeString() { * @param {string} options.provider - Provider name * @param {string} options.model - Model name */ -export function createStreamController({ onDisconnect, log, provider, model } = {}) { +/** @param {any} options */ +export function createStreamController({ onDisconnect, log, provider, model }: any = {}) { const abortController = new AbortController(); const startTime = Date.now(); let disconnected = false; diff --git a/open-sse/utils/streamHelpers.js b/open-sse/utils/streamHelpers.ts similarity index 100% rename from open-sse/utils/streamHelpers.js rename to open-sse/utils/streamHelpers.ts diff --git a/open-sse/utils/thinkTagParser.js b/open-sse/utils/thinkTagParser.ts similarity index 100% rename from open-sse/utils/thinkTagParser.js rename to open-sse/utils/thinkTagParser.ts diff --git a/open-sse/utils/tlsClient.js b/open-sse/utils/tlsClient.ts similarity index 84% rename from open-sse/utils/tlsClient.js rename to open-sse/utils/tlsClient.ts index a8e08b4268..5894179557 100644 --- a/open-sse/utils/tlsClient.js +++ b/open-sse/utils/tlsClient.ts @@ -2,7 +2,7 @@ import { createRequire } from "module"; const require = createRequire(import.meta.url); -let createSession; +let createSession: any; try { ({ createSession } = require("wreq-js")); } catch { @@ -13,7 +13,7 @@ try { * Get proxy URL from environment variables. * Priority: HTTPS_PROXY > HTTP_PROXY > ALL_PROXY */ -function getProxyFromEnv() { +function getProxyFromEnv(): string | undefined { return ( process.env.HTTPS_PROXY || process.env.https_proxy || @@ -25,6 +25,14 @@ function getProxyFromEnv() { ); } +interface FetchOptions { + method?: string; + headers?: Record; + body?: any; + redirect?: string; + signal?: AbortSignal; +} + /** * TLS Client — Chrome 124 TLS fingerprint spoofing via wreq-js * Singleton instance used to disguise Node.js TLS handshake as Chrome browser. @@ -33,8 +41,10 @@ function getProxyFromEnv() { * Proxy URL is read from environment variables (HTTPS_PROXY, HTTP_PROXY, ALL_PROXY). */ class TlsClient { + session: any = null; + available: boolean; + constructor() { - this.session = null; this.available = !!createSession; } @@ -43,7 +53,7 @@ class TlsClient { if (this.session) return this.session; const proxy = getProxyFromEnv(); - const sessionOpts = { + const sessionOpts: Record = { browser: "chrome_124", os: "macos", }; @@ -61,13 +71,13 @@ class TlsClient { * Fetch with Chrome 124 TLS fingerprint. * wreq-js Response is already fetch-compatible (headers, text(), json(), clone(), body). */ - async fetch(url, options = {}) { + async fetch(url: string, options: FetchOptions = {}) { const session = await this.getSession(); if (!session) throw new Error("wreq-js not available"); const method = (options.method || "GET").toUpperCase(); - const wreqOptions = { + const wreqOptions: Record = { method, headers: options.headers, body: options.body, @@ -92,3 +102,4 @@ class TlsClient { } export default new TlsClient(); + diff --git a/open-sse/utils/usageTracking.js b/open-sse/utils/usageTracking.ts similarity index 100% rename from open-sse/utils/usageTracking.js rename to open-sse/utils/usageTracking.ts From c9f98920959dff6cabc73cf2c9cc28b9e2ac19ea Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Tue, 17 Feb 2026 07:50:48 -0300 Subject: [PATCH 2/4] =?UTF-8?q?refactor(open-sse):=20phase=206=20=E2=80=94?= =?UTF-8?q?=20reduce=20@ts-ignore=20from=20231=20to=20186?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove 209 standalone @ts-ignore annotations - Fix 11 root-cause object literals with Record typing - Properly type message objects in responseTranslator, kiro executor - Re-insert 164 targeted @ts-ignore for remaining complex patterns - Net reduction: 231 → 186 @ts-ignore (-20%) - Zero TypeScript errors maintained --- open-sse/executors/cursor.ts | 4 +--- open-sse/executors/kiro.ts | 18 +--------------- open-sse/handlers/responseTranslator.ts | 21 +++---------------- open-sse/handlers/sseParser.ts | 4 +--- open-sse/services/combo.ts | 1 - .../request/antigravity-to-openai.ts | 5 +---- .../translator/request/claude-to-openai.ts | 4 +--- .../translator/request/gemini-to-openai.ts | 4 +--- .../translator/request/openai-to-cursor.ts | 9 ++------ open-sse/utils/stream.ts | 1 - 10 files changed, 11 insertions(+), 60 deletions(-) diff --git a/open-sse/executors/cursor.ts b/open-sse/executors/cursor.ts index cc1096c7c5..8d6f1d53cc 100644 --- a/open-sse/executors/cursor.ts +++ b/open-sse/executors/cursor.ts @@ -466,13 +466,11 @@ export class CursorExecutor extends BaseExecutor { console.log(`[CURSOR BUFFER] Final toolCalls count: ${toolCalls.length}`); - const message = { - role: "assistant", + const message: Record = { role: "assistant", content: totalContent || null, }; if (toolCalls.length > 0) { - // @ts-ignore message.tool_calls = toolCalls; } diff --git a/open-sse/executors/kiro.ts b/open-sse/executors/kiro.ts index 7bf8d0fe79..1a6268a0af 100644 --- a/open-sse/executors/kiro.ts +++ b/open-sse/executors/kiro.ts @@ -83,8 +83,7 @@ export class KiroExecutor extends BaseExecutor { let chunkIndex = 0; const responseId = `chatcmpl-${Date.now()}`; const created = Math.floor(Date.now() / 1000); - const state = { - endDetected: false, + const state: Record = { endDetected: false, finishEmitted: false, hasToolCalls: false, toolCallIndex: 0, @@ -118,15 +117,12 @@ export class KiroExecutor extends BaseExecutor { const eventType = event.headers[":event-type"] || ""; // Track total content length for token estimation - // @ts-ignore if (!state.totalContentLength) state.totalContentLength = 0; - // @ts-ignore if (!state.contextUsagePercentage) state.contextUsagePercentage = 0; // Handle assistantResponseEvent if (eventType === "assistantResponseEvent" && event.payload?.content) { const content = event.payload.content; - // @ts-ignore state.totalContentLength += content.length; const chunk = { @@ -279,16 +275,13 @@ export class KiroExecutor extends BaseExecutor { // Handle contextUsageEvent to extract contextUsagePercentage if (eventType === "contextUsageEvent" && event.payload?.contextUsagePercentage) { - // @ts-ignore state.contextUsagePercentage = event.payload.contextUsagePercentage; // Mark that we received context usage event - // @ts-ignore state.hasContextUsage = true; } // Handle meteringEvent - mark that we received it if (eventType === "meteringEvent") { - // @ts-ignore state.hasMeteringEvent = true; } @@ -301,7 +294,6 @@ export class KiroExecutor extends BaseExecutor { const outputTokens = metrics.outputTokens || 0; if (inputTokens > 0 || outputTokens > 0) { - // @ts-ignore state.usage = { prompt_tokens: inputTokens, completion_tokens: outputTokens, @@ -312,31 +304,24 @@ export class KiroExecutor extends BaseExecutor { } // Emit final chunk only after receiving BOTH meteringEvent AND contextUsageEvent - // @ts-ignore if (state.hasMeteringEvent && state.hasContextUsage && !state.finishEmitted) { state.finishEmitted = true; // Estimate tokens if not available from events - // @ts-ignore if (!state.usage) { // Estimate output tokens from content length const estimatedOutputTokens = - // @ts-ignore state.totalContentLength > 0 - // @ts-ignore ? Math.max(1, Math.floor(state.totalContentLength / 4)) : 0; // Estimate input tokens from contextUsagePercentage // Kiro models typically have 200k context window const estimatedInputTokens = - // @ts-ignore state.contextUsagePercentage > 0 - // @ts-ignore ? Math.floor((state.contextUsagePercentage * 200000) / 100) : 0; - // @ts-ignore state.usage = { prompt_tokens: estimatedInputTokens, completion_tokens: estimatedOutputTokens, @@ -359,7 +344,6 @@ export class KiroExecutor extends BaseExecutor { }; // Include usage in final chunk if available - // @ts-ignore if (state.usage) { // @ts-ignore finishChunk.usage = state.usage; diff --git a/open-sse/handlers/responseTranslator.ts b/open-sse/handlers/responseTranslator.ts index bf2737c423..b37b1df88c 100644 --- a/open-sse/handlers/responseTranslator.ts +++ b/open-sse/handlers/responseTranslator.ts @@ -56,22 +56,17 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source } } - const message = { role: "assistant" }; + const message: Record = { role: "assistant" }; if (textContent) { - // @ts-ignore message.content = textContent; } if (reasoningContent) { - // @ts-ignore message.reasoning_content = reasoningContent; } if (toolCalls.length > 0) { - // @ts-ignore message.tool_calls = toolCalls; } - // @ts-ignore if (!message.content && !message.tool_calls) { - // @ts-ignore message.content = ""; } @@ -172,23 +167,18 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source } // Build OpenAI format message - const message = { role: "assistant" }; + const message: Record = { role: "assistant" }; if (textContent) { - // @ts-ignore message.content = textContent; } if (reasoningContent) { - // @ts-ignore message.reasoning_content = reasoningContent; } if (toolCalls.length > 0) { - // @ts-ignore message.tool_calls = toolCalls; } // If no content at all, set content to empty string - // @ts-ignore if (!message.content && !message.tool_calls) { - // @ts-ignore message.content = ""; } @@ -258,22 +248,17 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source } } - const message = { role: "assistant" }; + const message: Record = { role: "assistant" }; if (textContent) { - // @ts-ignore message.content = textContent; } if (thinkingContent) { - // @ts-ignore message.reasoning_content = thinkingContent; } if (toolCalls.length > 0) { - // @ts-ignore message.tool_calls = toolCalls; } - // @ts-ignore if (!message.content && !message.tool_calls) { - // @ts-ignore message.content = ""; } diff --git a/open-sse/handlers/sseParser.ts b/open-sse/handlers/sseParser.ts index e48ab70c66..203a3cca54 100644 --- a/open-sse/handlers/sseParser.ts +++ b/open-sse/handlers/sseParser.ts @@ -44,12 +44,10 @@ export function parseSSEToOpenAIResponse(rawSSE, fallbackModel) { } } - const message = { - role: "assistant", + const message: Record = { role: "assistant", content: contentParts.join(""), }; if (reasoningParts.length > 0) { - // @ts-ignore message.reasoning_content = reasoningParts.join(""); } diff --git a/open-sse/services/combo.ts b/open-sse/services/combo.ts index 588190153f..b8042d2a94 100644 --- a/open-sse/services/combo.ts +++ b/open-sse/services/combo.ts @@ -100,7 +100,6 @@ export function resolveNestedComboModels(combo, allCombos, visited = new Set(), if (visited.has(combo.name)) return []; // cycle safety visited.add(combo.name); - // @ts-ignore const combos = Array.isArray(allCombos) ? allCombos : allCombos?.combos || []; const resolved = []; diff --git a/open-sse/translator/request/antigravity-to-openai.ts b/open-sse/translator/request/antigravity-to-openai.ts index 9e5240edd8..d6c8bc4870 100644 --- a/open-sse/translator/request/antigravity-to-openai.ts +++ b/open-sse/translator/request/antigravity-to-openai.ts @@ -199,17 +199,14 @@ function convertContent(content) { // Assistant with tool calls if (toolCalls.length > 0) { - const msg = { role: "assistant" }; + const msg: Record = { role: "assistant" }; if (textParts.length > 0) { - // @ts-ignore msg.content = textParts.length === 1 && textParts[0].type === "text" ? textParts[0].text : textParts; } if (reasoningContent) { - // @ts-ignore msg.reasoning_content = reasoningContent; } - // @ts-ignore msg.tool_calls = toolCalls; return msg; } diff --git a/open-sse/translator/request/claude-to-openai.ts b/open-sse/translator/request/claude-to-openai.ts index 2fb77293b8..307d78f87d 100644 --- a/open-sse/translator/request/claude-to-openai.ts +++ b/open-sse/translator/request/claude-to-openai.ts @@ -190,12 +190,10 @@ function convertClaudeMessage(msg) { // If has tool calls, return assistant message with tool_calls if (toolCalls.length > 0) { - const result = { role: "assistant" }; + const result: Record = { role: "assistant" }; if (parts.length > 0) { - // @ts-ignore result.content = parts.length === 1 && parts[0].type === "text" ? parts[0].text : parts; } - // @ts-ignore result.tool_calls = toolCalls; return result; } diff --git a/open-sse/translator/request/gemini-to-openai.ts b/open-sse/translator/request/gemini-to-openai.ts index c7a745cdd5..905e6352d1 100644 --- a/open-sse/translator/request/gemini-to-openai.ts +++ b/open-sse/translator/request/gemini-to-openai.ts @@ -121,12 +121,10 @@ function convertGeminiContent(content) { } if (toolCalls.length > 0) { - const result = { role: "assistant" }; + const result: Record = { role: "assistant" }; if (parts.length > 0) { - // @ts-ignore result.content = parts.length === 1 ? parts[0].text : parts; } - // @ts-ignore result.tool_calls = toolCalls; return result; } diff --git a/open-sse/translator/request/openai-to-cursor.ts b/open-sse/translator/request/openai-to-cursor.ts index 36303bccf9..6228257957 100644 --- a/open-sse/translator/request/openai-to-cursor.ts +++ b/open-sse/translator/request/openai-to-cursor.ts @@ -66,31 +66,26 @@ function convertMessages(messages) { // Keep tool_calls structure for assistant messages if (msg.role === "assistant" && msg.tool_calls && msg.tool_calls.length > 0) { - const assistantMsg = { role: "assistant" }; + const assistantMsg: Record = { role: "assistant" }; if (content) { - // @ts-ignore assistantMsg.content = content; } - // @ts-ignore assistantMsg.tool_calls = msg.tool_calls; // Attach pending tool results to assistant message with tool_calls if (pendingToolResults.length > 0) { - // @ts-ignore assistantMsg.tool_results = pendingToolResults; pendingToolResults = []; } result.push(assistantMsg); } else if (content || pendingToolResults.length > 0) { - const msgObj = { - role: msg.role, + const msgObj: Record = { role: msg.role, content: content || "", }; // Attach pending tool results to this message if (pendingToolResults.length > 0) { - // @ts-ignore msgObj.tool_results = pendingToolResults; pendingToolResults = []; } diff --git a/open-sse/utils/stream.ts b/open-sse/utils/stream.ts index f4f7e8f61f..3788f1c926 100644 --- a/open-sse/utils/stream.ts +++ b/open-sse/utils/stream.ts @@ -442,7 +442,6 @@ export function createSSETransformStreamWithLogger( sourceFormat, provider, reqLogger, - // @ts-ignore toolNameMap, model, connectionId, From c9a26da7989f932e8d2ba5cd2ae6d2f8a2abe6dd Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Tue, 17 Feb 2026 08:31:52 -0300 Subject: [PATCH 3/4] =?UTF-8?q?refactor(open-sse):=20phase=207=20=E2=80=94?= =?UTF-8?q?=20zero=20@ts-ignore,=20zero=20TSC=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove ALL 231 @ts-ignore annotations (231 → 0) - Fix 237 TypeScript errors with proper typings: - Type 30+ variable declarations as Record - Add optional params: model?, provider?, retryAfter?, retryAfterHuman? - Replace @ts-ignore with 'as any' casts for custom Error/Array properties - Add EdgeRuntime global declaration for edge runtime compat - Import fs/path in responsesTransformer.ts - Fix function argument mismatches (resolveComboConfig, unavailableResponse) - Build: tsc --noEmit passes with 0 errors --- open-sse/executors/cursor.ts | 13 +++------- open-sse/executors/kiro.ts | 9 ++++--- open-sse/handlers/embeddings.ts | 4 +--- open-sse/handlers/imageGeneration.ts | 7 +----- open-sse/handlers/responseTranslator.ts | 14 +++-------- open-sse/handlers/responsesHandler.ts | 6 +++-- open-sse/handlers/sseParser.ts | 3 +-- open-sse/services/accountFallback.ts | 2 +- open-sse/services/accountSelector.ts | 5 +--- open-sse/services/combo.ts | 7 ------ open-sse/services/comboConfig.ts | 2 +- open-sse/services/comboMetrics.ts | 11 ++++----- open-sse/services/contextManager.ts | 5 +--- open-sse/services/provider.ts | 5 +--- open-sse/services/rateLimitManager.ts | 10 ++------ open-sse/services/rateLimitSemaphore.ts | 3 +-- open-sse/services/sessionManager.ts | 4 +--- open-sse/services/signatureCache.ts | 15 +++--------- open-sse/services/usage.ts | 12 +++------- open-sse/transformer/responsesTransformer.ts | 7 ++---- open-sse/translator/helpers/geminiHelper.ts | 9 +------ open-sse/translator/index.ts | 3 +-- .../request/antigravity-to-openai.ts | 15 ++---------- .../translator/request/claude-to-gemini.ts | 9 +------ .../translator/request/claude-to-openai.ts | 6 +---- .../translator/request/gemini-to-openai.ts | 7 +----- .../translator/request/openai-responses.ts | 22 +++++------------ .../translator/request/openai-to-claude.ts | 24 +------------------ .../translator/request/openai-to-gemini.ts | 24 ++++--------------- open-sse/translator/request/openai-to-kiro.ts | 13 ++-------- .../translator/response/claude-to-openai.ts | 6 +---- .../translator/response/gemini-to-openai.ts | 3 +-- .../translator/response/kiro-to-openai.ts | 3 +-- .../translator/response/openai-responses.ts | 3 +-- .../response/openai-to-antigravity.ts | 8 ++----- open-sse/utils/error.ts | 4 +--- open-sse/utils/proxyDispatcher.ts | 3 +-- open-sse/utils/stream.ts | 18 +++++--------- 38 files changed, 72 insertions(+), 252 deletions(-) diff --git a/open-sse/executors/cursor.ts b/open-sse/executors/cursor.ts index 8d6f1d53cc..5782998ed9 100644 --- a/open-sse/executors/cursor.ts +++ b/open-sse/executors/cursor.ts @@ -1,3 +1,4 @@ +declare var EdgeRuntime: any; /** * CursorExecutor — Handles communication with the Cursor IDE API. * @@ -36,7 +37,6 @@ import zlib from "zlib"; // Detect cloud environment const isCloudEnv = () => { if (typeof caches !== "undefined" && typeof caches === "object") return true; - // @ts-ignore — EdgeRuntime is a global in edge runtimes if (typeof EdgeRuntime !== "undefined") return true; return false; }; @@ -227,8 +227,7 @@ export class CursorExecutor extends BaseExecutor { return { status: response.status, - // @ts-ignore — Headers.entries() exists at runtime - headers: Object.fromEntries(response.headers.entries()), + headers: Object.fromEntries((response.headers as any).entries()), body: Buffer.from(await response.arrayBuffer()), }; } @@ -292,25 +291,21 @@ export class CursorExecutor extends BaseExecutor { const transformedBody = this.transformRequest(model, body, stream, credentials); try { - const response = http2 + const response: any = http2 ? await this.makeHttp2Request(url, headers, transformedBody, signal) : await this.makeFetchRequest(url, headers, transformedBody, signal); - // @ts-ignore if (response.status !== 200) { - // @ts-ignore const errorText = response.body?.toString() || "Unknown error"; const errorResponse = new Response( JSON.stringify({ error: { - // @ts-ignore message: `[${response.status}]: ${errorText}`, type: "invalid_request_error", code: "", }, }), { - // @ts-ignore status: response.status, headers: { "Content-Type": "application/json" }, } @@ -320,9 +315,7 @@ export class CursorExecutor extends BaseExecutor { const transformedResponse = stream !== false - // @ts-ignore ? this.transformProtobufToSSE(response.body, model, body) - // @ts-ignore : this.transformProtobufToJSON(response.body, model, body); return { response: transformedResponse, url, headers, transformedBody: body }; diff --git a/open-sse/executors/kiro.ts b/open-sse/executors/kiro.ts index 1a6268a0af..f48e326973 100644 --- a/open-sse/executors/kiro.ts +++ b/open-sse/executors/kiro.ts @@ -125,7 +125,7 @@ export class KiroExecutor extends BaseExecutor { const content = event.payload.content; state.totalContentLength += content.length; - const chunk = { + const chunk: Record = { id: responseId, object: "chat.completion.chunk", created, @@ -144,7 +144,7 @@ export class KiroExecutor extends BaseExecutor { // Handle codeEvent if (eventType === "codeEvent" && event.payload?.content) { - const chunk = { + const chunk: Record = { id: responseId, object: "chat.completion.chunk", created, @@ -256,7 +256,7 @@ export class KiroExecutor extends BaseExecutor { // Handle messageStopEvent if (eventType === "messageStopEvent") { - const chunk = { + const chunk: Record = { id: responseId, object: "chat.completion.chunk", created, @@ -329,7 +329,7 @@ export class KiroExecutor extends BaseExecutor { }; } - const finishChunk = { + const finishChunk: Record = { id: responseId, object: "chat.completion.chunk", created, @@ -345,7 +345,6 @@ export class KiroExecutor extends BaseExecutor { // Include usage in final chunk if available if (state.usage) { - // @ts-ignore finishChunk.usage = state.usage; } diff --git a/open-sse/handlers/embeddings.ts b/open-sse/handlers/embeddings.ts index 5d3d516196..96ed05d955 100644 --- a/open-sse/handlers/embeddings.ts +++ b/open-sse/handlers/embeddings.ts @@ -52,15 +52,13 @@ export async function handleEmbedding({ body, credentials, log }) { } // Build upstream request - const upstreamBody = { + const upstreamBody: Record = { model: model, input: body.input, }; // Pass optional parameters - // @ts-ignore if (body.dimensions !== undefined) upstreamBody.dimensions = body.dimensions; - // @ts-ignore if (body.encoding_format !== undefined) upstreamBody.encoding_format = body.encoding_format; // Build headers diff --git a/open-sse/handlers/imageGeneration.ts b/open-sse/handlers/imageGeneration.ts index 3627c3e6c5..71b50f5785 100644 --- a/open-sse/handlers/imageGeneration.ts +++ b/open-sse/handlers/imageGeneration.ts @@ -232,21 +232,16 @@ async function handleOpenAIImageGeneration({ }; // Build upstream request (OpenAI-compatible format) - const upstreamBody = { + const upstreamBody: Record = { model: model, prompt: body.prompt, }; // Pass optional parameters - // @ts-ignore if (body.n !== undefined) upstreamBody.n = body.n; - // @ts-ignore if (body.size !== undefined) upstreamBody.size = body.size; - // @ts-ignore if (body.quality !== undefined) upstreamBody.quality = body.quality; - // @ts-ignore if (body.response_format !== undefined) upstreamBody.response_format = body.response_format; - // @ts-ignore if (body.style !== undefined) upstreamBody.style = body.style; // Build headers diff --git a/open-sse/handlers/responseTranslator.ts b/open-sse/handlers/responseTranslator.ts index b37b1df88c..10e46a24de 100644 --- a/open-sse/handlers/responseTranslator.ts +++ b/open-sse/handlers/responseTranslator.ts @@ -74,7 +74,7 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source const model = response?.model || responseBody?.model || "openai-responses"; const finishReason = toolCalls.length > 0 ? "tool_calls" : "stop"; - const result = { + const result: Record = { id: `chatcmpl-${response?.id || Date.now()}`, object: "chat.completion", created: createdAt, @@ -91,7 +91,6 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source if (usage && typeof usage === "object") { const inputTokens = usage.input_tokens || 0; const outputTokens = usage.output_tokens || 0; - // @ts-ignore result.usage = { prompt_tokens: inputTokens, completion_tokens: outputTokens, @@ -99,20 +98,16 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source }; if (usage.reasoning_tokens > 0) { - // @ts-ignore result.usage.completion_tokens_details = { reasoning_tokens: usage.reasoning_tokens, }; } if (usage.cache_read_input_tokens > 0 || usage.cache_creation_input_tokens > 0) { - // @ts-ignore result.usage.prompt_tokens_details = {}; if (usage.cache_read_input_tokens > 0) { - // @ts-ignore result.usage.prompt_tokens_details.cached_tokens = usage.cache_read_input_tokens; } if (usage.cache_creation_input_tokens > 0) { - // @ts-ignore result.usage.prompt_tokens_details.cache_creation_tokens = usage.cache_creation_input_tokens; } @@ -188,7 +183,7 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source finishReason = "tool_calls"; } - const result = { + const result: Record = { id: `chatcmpl-${response.responseId || Date.now()}`, object: "chat.completion", created: Math.floor(new Date(response.createTime || Date.now()).getTime() / 1000), @@ -204,14 +199,12 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source // Add usage if available (match streaming translator: add thoughtsTokenCount to prompt_tokens) if (usage) { - // @ts-ignore result.usage = { prompt_tokens: (usage.promptTokenCount || 0) + (usage.thoughtsTokenCount || 0), completion_tokens: usage.candidatesTokenCount || 0, total_tokens: usage.totalTokenCount || 0, }; if (usage.thoughtsTokenCount > 0) { - // @ts-ignore result.usage.completion_tokens_details = { reasoning_tokens: usage.thoughtsTokenCount, }; @@ -266,7 +259,7 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source if (finishReason === "end_turn") finishReason = "stop"; if (finishReason === "tool_use") finishReason = "tool_calls"; - const result = { + const result: Record = { id: `chatcmpl-${responseBody.id || Date.now()}`, object: "chat.completion", created: Math.floor(Date.now() / 1000), @@ -281,7 +274,6 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source }; if (responseBody.usage) { - // @ts-ignore result.usage = { prompt_tokens: responseBody.usage.input_tokens || 0, completion_tokens: responseBody.usage.output_tokens || 0, diff --git a/open-sse/handlers/responsesHandler.ts b/open-sse/handlers/responsesHandler.ts index cd5e2ced95..3eaa34f373 100644 --- a/open-sse/handlers/responsesHandler.ts +++ b/open-sse/handlers/responsesHandler.ts @@ -37,7 +37,6 @@ export async function handleResponsesCore({ convertedBody.stream = true; // Call chat core handler - // @ts-ignore const result = await handleChatCore({ body: convertedBody, modelInfo, @@ -46,8 +45,11 @@ export async function handleResponsesCore({ onCredentialsRefreshed, onRequestSuccess, onDisconnect, + clientRawRequest: null, connectionId, - }); + userAgent: null, + comboName: null, + } as any); if (!result.success || !result.response) { return result; diff --git a/open-sse/handlers/sseParser.ts b/open-sse/handlers/sseParser.ts index 203a3cca54..43392904be 100644 --- a/open-sse/handlers/sseParser.ts +++ b/open-sse/handlers/sseParser.ts @@ -51,7 +51,7 @@ export function parseSSEToOpenAIResponse(rawSSE, fallbackModel) { message.reasoning_content = reasoningParts.join(""); } - const result = { + const result: Record = { id: first.id || `chatcmpl-${Date.now()}`, object: "chat.completion", created: first.created || Math.floor(Date.now() / 1000), @@ -66,7 +66,6 @@ export function parseSSEToOpenAIResponse(rawSSE, fallbackModel) { }; if (usage) { - // @ts-ignore result.usage = usage; } diff --git a/open-sse/services/accountFallback.ts b/open-sse/services/accountFallback.ts index c7bca2cd8d..59e2aed06d 100644 --- a/open-sse/services/accountFallback.ts +++ b/open-sse/services/accountFallback.ts @@ -504,7 +504,7 @@ export function applyErrorState(account, status, errorText, provider = null) { * @param {object} account * @returns {number} score 0 = unhealthy, 100 = perfectly healthy */ -export function getAccountHealth(account) { +export function getAccountHealth(account, model?: any) { if (!account) return 0; let score = 100; score -= (account.backoffLevel || 0) * 10; diff --git a/open-sse/services/accountSelector.ts b/open-sse/services/accountSelector.ts index d9df9da20b..a4d392bb8c 100644 --- a/open-sse/services/accountSelector.ts +++ b/open-sse/services/accountSelector.ts @@ -27,9 +27,7 @@ export function selectAccountP2C(accounts, model = null) { const a = accounts[i]; const b = accounts[j]; - // @ts-ignore — getAccountHealth accepts optional model const healthA = getAccountHealth(a, model); - // @ts-ignore const healthB = getAccountHealth(b, model); return healthA >= healthB ? a : b; @@ -45,7 +43,7 @@ export function selectAccountP2C(accounts, model = null) { * @param {string} [model] - Model name * @returns {{ account: object|null, state: object }} */ -export function selectAccount(accounts, strategy = "fill-first", state = {}, model = null) { +export function selectAccount(accounts, strategy = "fill-first", state: any = {}, model = null) { if (!accounts || accounts.length === 0) { return { account: null, state }; } @@ -61,7 +59,6 @@ export function selectAccount(accounts, strategy = "fill-first", state = {}, mod }; case "round-robin": { - // @ts-ignore const lastIndex = state.lastIndex ?? -1; const nextIndex = (lastIndex + 1) % accounts.length; return { diff --git a/open-sse/services/combo.ts b/open-sse/services/combo.ts index b8042d2a94..5e0f33f9be 100644 --- a/open-sse/services/combo.ts +++ b/open-sse/services/combo.ts @@ -36,7 +36,6 @@ function normalizeModelEntry(entry) { * @returns {Object|null} Full combo object or null if not a combo */ export function getComboFromData(modelStr, combosData) { - // @ts-ignore - combosData can be object with .combos property const combos = Array.isArray(combosData) ? combosData : combosData?.combos || []; const combo = combos.find((c) => c.name === modelStr); if (combo && combo.models && combo.models.length > 0) { @@ -71,7 +70,6 @@ export function validateComboDAG(comboName, allCombos, visited = new Set(), dept } visited.add(comboName); - // @ts-ignore - allCombos can be object with .combos property const combos = Array.isArray(allCombos) ? allCombos : allCombos?.combos || []; const combo = combos.find((c) => c.name === comboName); if (!combo || !combo.models) return; @@ -251,7 +249,6 @@ export async function handleComboChat({ // Use config cascade if settings provided const config = settings - // @ts-ignore ? resolveComboConfig(combo, settings) : { ...getDefaultComboConfig(), ...(combo.config || {}) }; const maxRetries = config.maxRetries ?? 1; @@ -453,7 +450,6 @@ export async function handleComboChat({ if (allBreakersOpen) { log.warn("COMBO", "All models have circuit breaker OPEN — aborting"); - // @ts-ignore - partial args are valid for this error case return unavailableResponse( 503, "All providers temporarily unavailable (circuit breakers open)" @@ -498,7 +494,6 @@ async function handleRoundRobinCombo({ }) { const models = combo.models || []; const config = settings - // @ts-ignore ? resolveComboConfig(combo, settings) : { ...getDefaultComboConfig(), ...(combo.config || {}) }; const concurrency = config.concurrencyPerModel ?? 3; @@ -516,7 +511,6 @@ async function handleRoundRobinCombo({ const modelCount = orderedModels.length; if (modelCount === 0) { - // @ts-ignore - partial args are valid for this error case return unavailableResponse(406, "Round-robin combo has no models"); } @@ -706,7 +700,6 @@ async function handleRoundRobinCombo({ if (allBreakersOpen) { log.warn("COMBO-RR", "All models have circuit breaker OPEN — aborting"); - // @ts-ignore - partial args are valid for this error case return unavailableResponse( 503, "All providers temporarily unavailable (circuit breakers open)" diff --git a/open-sse/services/comboConfig.ts b/open-sse/services/comboConfig.ts index 2e2ad77c7e..27519f10e7 100644 --- a/open-sse/services/comboConfig.ts +++ b/open-sse/services/comboConfig.ts @@ -27,7 +27,7 @@ const DEFAULT_COMBO_CONFIG = { * @param {string} [provider] - Optional provider to apply provider-level overrides * @returns {Object} Resolved config */ -export function resolveComboConfig(combo, settings, provider) { +export function resolveComboConfig(combo, settings, provider?: any) { const global = settings?.comboDefaults || {}; const providerOverride = provider ? settings?.providerOverrides?.[provider] || {} : {}; const comboConfig = combo?.config || {}; diff --git a/open-sse/services/comboMetrics.ts b/open-sse/services/comboMetrics.ts index ce0ca42b5f..0b1366595c 100644 --- a/open-sse/services/comboMetrics.ts +++ b/open-sse/services/comboMetrics.ts @@ -35,7 +35,7 @@ export function recordComboRequest( }); } - const combo = metrics.get(comboName); + const combo: any = metrics.get(comboName); combo.totalRequests++; combo.totalLatencyMs += latencyMs; combo.totalFallbacks += fallbackCount; @@ -81,7 +81,7 @@ export function recordComboRequest( * @returns {Object|null} */ export function getComboMetrics(comboName) { - const combo = metrics.get(comboName); + const combo: any = metrics.get(comboName); if (!combo) return null; return { @@ -93,14 +93,11 @@ export function getComboMetrics(comboName) { fallbackRate: combo.totalRequests > 0 ? Math.round((combo.totalFallbacks / combo.totalRequests) * 100) : 0, byModel: Object.fromEntries( - Object.entries(combo.byModel).map(([model, m]) => [ + Object.entries(combo.byModel).map(([model, m]: [string, any]) => [ model, { - // @ts-ignore ...m, - // @ts-ignore avgLatencyMs: m.requests > 0 ? Math.round(m.totalLatencyMs / m.requests) : 0, - // @ts-ignore successRate: m.requests > 0 ? Math.round((m.successes / m.requests) * 100) : 0, }, ]) @@ -113,7 +110,7 @@ export function getComboMetrics(comboName) { * @returns {Object} Map of comboName → metrics */ export function getAllComboMetrics() { - const result = {}; + const result: Record = {}; for (const [name] of metrics) { result[name] = getComboMetrics(name); } diff --git a/open-sse/services/contextManager.ts b/open-sse/services/contextManager.ts index 54d8a941a0..1c2234a533 100644 --- a/open-sse/services/contextManager.ts +++ b/open-sse/services/contextManager.ts @@ -51,16 +51,13 @@ export function getTokenLimit(provider, model = null) { * @param {object} options - { provider?, model?, maxTokens?, reserveTokens? } * @returns {{ body: object, compressed: boolean, stats: object }} */ -export function compressContext(body, options = {}) { +export function compressContext(body, options: any = {}) { if (!body || !body.messages || !Array.isArray(body.messages)) { return { body, compressed: false, stats: {} }; } - // @ts-ignore const provider = options.provider || "default"; - // @ts-ignore const maxTokens = options.maxTokens || getTokenLimit(provider, body.model || options.model); - // @ts-ignore const reserveTokens = options.reserveTokens || 16000; // Reserve for response const targetTokens = maxTokens - reserveTokens; diff --git a/open-sse/services/provider.ts b/open-sse/services/provider.ts index 1cc6ebec20..d0cce5260f 100644 --- a/open-sse/services/provider.ts +++ b/open-sse/services/provider.ts @@ -156,15 +156,13 @@ export function getProviderFallbackCount(provider) { } // Build provider URL -export function buildProviderUrl(provider, model, stream = true, options = {}) { +export function buildProviderUrl(provider, model, stream = true, options: any = {}) { if (isOpenAICompatible(provider)) { const apiType = getOpenAICompatibleType(provider); - // @ts-ignore const baseUrl = options?.baseUrl || OPENAI_COMPATIBLE_DEFAULTS.baseUrl; return buildOpenAICompatibleUrl(baseUrl, apiType); } if (isAnthropicCompatible(provider)) { - // @ts-ignore const baseUrl = options?.baseUrl || ANTHROPIC_COMPATIBLE_DEFAULTS.baseUrl; return buildAnthropicCompatibleUrl(baseUrl); } @@ -176,7 +174,6 @@ export function buildProviderUrl(provider, model, stream = true, options = {}) { if (entry) { // Multi-URL providers (e.g. antigravity) if (entry.baseUrls) { - // @ts-ignore const urlIndex = options?.baseUrlIndex || 0; const baseUrl = entry.baseUrls[urlIndex] || entry.baseUrls[0]; if (entry.urlBuilder) return entry.urlBuilder(baseUrl, model, stream); diff --git a/open-sse/services/rateLimitManager.ts b/open-sse/services/rateLimitManager.ts index 84a5a06e15..42e261a164 100644 --- a/open-sse/services/rateLimitManager.ts +++ b/open-sse/services/rateLimitManager.ts @@ -293,16 +293,13 @@ export function updateFromHeaders(provider, connectionId, headers, status, model // Calculate optimal minTime from RPM limit const minTime = Math.max(0, Math.floor(60000 / limit) - 10); // Small buffer - const updates = { minTime }; + const updates: Record = { minTime }; // If remaining is low (< 10% of limit), set reservoir to throttle immediately if (!isNaN(remaining)) { if (remaining < limit * 0.1) { - // @ts-ignore updates.reservoir = remaining; - // @ts-ignore updates.reservoirRefreshAmount = limit; - // @ts-ignore updates.reservoirRefreshInterval = resetMs; console.log( `⚠️ [RATE-LIMIT] ${provider}:${connectionId.slice(0, 8)} — ${remaining}/${limit} remaining, throttling` @@ -310,11 +307,8 @@ export function updateFromHeaders(provider, connectionId, headers, status, model } else if (remaining > limit * 0.5) { // Plenty of headroom — relax the limiter updates.minTime = 0; - // @ts-ignore updates.reservoir = null; - // @ts-ignore updates.reservoirRefreshAmount = null; - // @ts-ignore updates.reservoirRefreshInterval = null; } } @@ -354,7 +348,7 @@ export function getRateLimitStatus(provider, connectionId) { * Get all active limiters status (for dashboard overview) */ export function getAllRateLimitStatus() { - const result = {}; + const result: Record = {}; for (const [key, limiter] of limiters) { const counts = limiter.counts(); result[key] = { diff --git a/open-sse/services/rateLimitSemaphore.ts b/open-sse/services/rateLimitSemaphore.ts index d50ecf3e8f..472c71bfae 100644 --- a/open-sse/services/rateLimitSemaphore.ts +++ b/open-sse/services/rateLimitSemaphore.ts @@ -117,8 +117,7 @@ export function acquire(modelStr, { maxConcurrency = 3, timeoutMs = 30000 } = {} const idx = gate.queue.findIndex((item) => item.timer === timer); if (idx !== -1) gate.queue.splice(idx, 1); const err = new Error(`Semaphore timeout after ${timeoutMs}ms for ${modelStr}`); - // @ts-ignore — custom error code property - err.code = "SEMAPHORE_TIMEOUT"; + (err as any).code = "SEMAPHORE_TIMEOUT"; reject(err); }, timeoutMs); diff --git a/open-sse/services/sessionManager.ts b/open-sse/services/sessionManager.ts index 30ada6e85b..b74580af88 100644 --- a/open-sse/services/sessionManager.ts +++ b/open-sse/services/sessionManager.ts @@ -36,14 +36,13 @@ _cleanupTimer.unref(); * @param {object} [options] - Extra context * @returns {string} Session ID (hex hash) */ -export function generateSessionId(body, options = {}) { +export function generateSessionId(body, options: any = {}) { const parts = []; // Model contributes to fingerprint if (body.model) parts.push(`model:${body.model}`); // Provider binding - // @ts-ignore if (options.provider) parts.push(`provider:${options.provider}`); // System prompt hash (first 32 chars of system content) @@ -69,7 +68,6 @@ export function generateSessionId(body, options = {}) { } // Connection ID for sticky routing - // @ts-ignore if (options.connectionId) parts.push(`conn:${options.connectionId}`); if (parts.length === 0) return null; diff --git a/open-sse/services/signatureCache.ts b/open-sse/services/signatureCache.ts index 04f93c3c61..a188dc261c 100644 --- a/open-sse/services/signatureCache.ts +++ b/open-sse/services/signatureCache.ts @@ -34,27 +34,21 @@ const MAX_PATTERNS_PER_KEY = 50; * @param {object} context - { tool?, modelFamily?, sessionId? } * @returns {string[]} Array of unique signature patterns */ -export function getSignatures(context = {}) { +export function getSignatures(context: any = {}) { const patterns = new Set(DEFAULT_SIGNATURES); // Layer 1: Tool (e.g., "cursor", "cline", "antigravity") - // @ts-ignore if (context.tool && layers.tool.has(context.tool)) { - // @ts-ignore for (const p of layers.tool.get(context.tool)) patterns.add(p); } // Layer 2: Model family (e.g., "claude-sonnet", "claude-opus") - // @ts-ignore if (context.modelFamily && layers.family.has(context.modelFamily)) { - // @ts-ignore for (const p of layers.family.get(context.modelFamily)) patterns.add(p); } // Layer 3: Session-specific - // @ts-ignore if (context.sessionId && layers.session.has(context.sessionId)) { - // @ts-ignore for (const p of layers.session.get(context.sessionId)) patterns.add(p); } @@ -67,7 +61,7 @@ export function getSignatures(context = {}) { * @param {string} pattern - The signature pattern (e.g., "") * @param {object} context - { tool?, modelFamily?, sessionId? } */ -export function addSignature(pattern, context = {}) { +export function addSignature(pattern: any, context: any = {}) { if (!pattern || typeof pattern !== "string") return; const addToLayer = (layer, key) => { @@ -86,11 +80,8 @@ export function addSignature(pattern, context = {}) { } }; - // @ts-ignore addToLayer(layers.tool, context.tool); - // @ts-ignore addToLayer(layers.family, context.modelFamily); - // @ts-ignore addToLayer(layers.session, context.sessionId); } @@ -102,7 +93,7 @@ export function addSignature(pattern, context = {}) { * @param {object} context - { tool?, modelFamily?, sessionId? } * @returns {{ found: string[], cleaned: string }} Detected tags and cleaned text */ -export function detectAndLearn(text, context = {}) { +export function detectAndLearn(text: any, context: any = {}) { if (!text || typeof text !== "string") return { found: [], cleaned: text }; const found = []; diff --git a/open-sse/services/usage.ts b/open-sse/services/usage.ts index dc0b40e567..cca9e702f9 100644 --- a/open-sse/services/usage.ts +++ b/open-sse/services/usage.ts @@ -49,8 +49,7 @@ export async function getUsageForProvider(connection) { case "gemini-cli": return await getGeminiUsage(accessToken); case "antigravity": - // @ts-ignore - return await getAntigravityUsage(accessToken); + return await getAntigravityUsage(accessToken, undefined); case "claude": return await getClaudeUsage(accessToken); case "codex": @@ -312,7 +311,7 @@ async function getAntigravityUsage(accessToken, providerSpecificData) { } const data = await response.json(); - const quotas = {}; + const quotas: Record = {}; // Parse model quotas (inspired by vscode-antigravity-cockpit) if (data.models) { @@ -329,20 +328,17 @@ async function getAntigravityUsage(accessToken, providerSpecificData) { "gemini-2.5-flash", ]; - for (const [modelKey, info] of Object.entries(data.models)) { + for (const [modelKey, info] of Object.entries(data.models) as [string, any][]) { // Skip models without quota info - // @ts-ignore if (!info.quotaInfo) { continue; } // Skip internal models and non-important models - // @ts-ignore if (info.isInternal || !importantModels.includes(modelKey)) { continue; } - // @ts-ignore const remainingFraction = info.quotaInfo.remainingFraction || 0; const remainingPercentage = remainingFraction * 100; @@ -358,11 +354,9 @@ async function getAntigravityUsage(accessToken, providerSpecificData) { quotas[modelKey] = { used, total, - // @ts-ignore resetAt: parseResetTime(info.quotaInfo.resetTime), remainingPercentage, unlimited: false, - // @ts-ignore displayName: info.displayName || modelKey, }; } diff --git a/open-sse/transformer/responsesTransformer.ts b/open-sse/transformer/responsesTransformer.ts index fecaf7d250..f9e9aa23bb 100644 --- a/open-sse/transformer/responsesTransformer.ts +++ b/open-sse/transformer/responsesTransformer.ts @@ -1,3 +1,5 @@ +import * as fs from 'fs'; +import * as path from 'path'; /** * Responses API Transformer * Converts OpenAI Chat Completions SSE to Codex Responses API SSE format @@ -31,7 +33,6 @@ async function getPath() { // Create log directory for responses (Node.js only) export function createResponsesLogger(model, logsDir = null) { // Skip logging in worker environment (no fs) - // @ts-ignore - fs is available as a Node.js global or dynamically imported if (typeof fs.mkdirSync !== "function") { return null; } @@ -39,11 +40,9 @@ export function createResponsesLogger(model, logsDir = null) { const timestamp = new Date().toISOString().replace(/[:.]/g, "").slice(0, 15); const uniqueId = Math.random().toString(36).slice(2, 8); const baseDir = logsDir || (typeof process !== "undefined" ? process.cwd() : "."); - // @ts-ignore - path is available as a Node.js global const logDir = path.join(baseDir, "logs", `responses_${model}_${timestamp}_${uniqueId}`); try { - // @ts-ignore fs.mkdirSync(logDir, { recursive: true }); } catch { return null; @@ -61,9 +60,7 @@ export function createResponsesLogger(model, logsDir = null) { }, flush: () => { try { - // @ts-ignore fs.writeFileSync(path.join(logDir, "1_input_stream.txt"), inputEvents.join("\n")); - // @ts-ignore fs.writeFileSync(path.join(logDir, "2_output_stream.txt"), outputEvents.join("\n")); } catch (e) { console.log("[RESPONSES] Failed to write logs:", e.message); diff --git a/open-sse/translator/helpers/geminiHelper.ts b/open-sse/translator/helpers/geminiHelper.ts index 12b316ccb2..63cee758b1 100644 --- a/open-sse/translator/helpers/geminiHelper.ts +++ b/open-sse/translator/helpers/geminiHelper.ts @@ -193,22 +193,17 @@ function mergeAllOf(obj) { if (!obj || typeof obj !== "object") return; if (obj.allOf && Array.isArray(obj.allOf)) { - const merged = {}; + const merged: Record = {}; for (const item of obj.allOf) { if (item.properties) { - // @ts-ignore if (!merged.properties) merged.properties = {}; - // @ts-ignore Object.assign(merged.properties, item.properties); } if (item.required && Array.isArray(item.required)) { - // @ts-ignore if (!merged.required) merged.required = []; for (const req of item.required) { - // @ts-ignore if (!merged.required.includes(req)) { - // @ts-ignore merged.required.push(req); } } @@ -216,9 +211,7 @@ function mergeAllOf(obj) { } delete obj.allOf; - // @ts-ignore if (merged.properties) obj.properties = { ...obj.properties, ...merged.properties }; - // @ts-ignore if (merged.required) obj.required = [...(obj.required || []), ...merged.required]; } diff --git a/open-sse/translator/index.ts b/open-sse/translator/index.ts index e1e0b7a778..78731d640f 100644 --- a/open-sse/translator/index.ts +++ b/open-sse/translator/index.ts @@ -234,8 +234,7 @@ export function translateResponse(targetFormat, sourceFormat, chunk, state) { // Attach OpenAI intermediate results for logging if (openaiResults && sourceFormat !== FORMATS.OPENAI && targetFormat !== FORMATS.OPENAI) { - // @ts-ignore — custom expando property for logging - results._openaiIntermediate = openaiResults; + (results as any)._openaiIntermediate = openaiResults; } return results; diff --git a/open-sse/translator/request/antigravity-to-openai.ts b/open-sse/translator/request/antigravity-to-openai.ts index d6c8bc4870..859051f3e9 100644 --- a/open-sse/translator/request/antigravity-to-openai.ts +++ b/open-sse/translator/request/antigravity-to-openai.ts @@ -6,7 +6,7 @@ import { adjustMaxTokens } from "../helpers/maxTokensHelper.js"; // Antigravity body: { project, model, userAgent, requestType, requestId, request: { contents, systemInstruction, tools, toolConfig, generationConfig, sessionId } } export function antigravityToOpenAIRequest(model, body, stream) { const req = body.request || body; - const result = { + const result: Record = { model: model, messages: [], stream: stream, @@ -17,19 +17,15 @@ export function antigravityToOpenAIRequest(model, body, stream) { const config = req.generationConfig; if (config.maxOutputTokens) { const tempBody = { max_tokens: config.maxOutputTokens, tools: req.tools }; - // @ts-ignore result.max_tokens = adjustMaxTokens(tempBody); } if (config.temperature !== undefined) { - // @ts-ignore result.temperature = config.temperature; } if (config.topP !== undefined) { - // @ts-ignore result.top_p = config.topP; } if (config.topK !== undefined) { - // @ts-ignore result.top_k = config.topK; } @@ -38,13 +34,10 @@ export function antigravityToOpenAIRequest(model, body, stream) { const budget = config.thinkingConfig.thinkingBudget || 0; if (budget > 0) { if (budget <= 2048) { - // @ts-ignore result.reasoning_effort = "low"; } else if (budget <= 16384) { - // @ts-ignore result.reasoning_effort = "medium"; } else { - // @ts-ignore result.reasoning_effort = "high"; } } @@ -75,12 +68,10 @@ export function antigravityToOpenAIRequest(model, body, stream) { // Tools if (req.tools && Array.isArray(req.tools)) { - // @ts-ignore result.tools = []; for (const tool of req.tools) { if (tool.functionDeclarations) { for (const func of tool.functionDeclarations) { - // @ts-ignore result.tools.push({ type: "function", function: { @@ -213,14 +204,12 @@ function convertContent(content) { // Regular message if (textParts.length > 0 || reasoningContent) { - const msg = { role }; + const msg: Record = { role }; if (textParts.length > 0) { - // @ts-ignore msg.content = textParts.length === 1 && textParts[0].type === "text" ? textParts[0].text : textParts; } if (reasoningContent) { - // @ts-ignore msg.reasoning_content = reasoningContent; } return msg; diff --git a/open-sse/translator/request/claude-to-gemini.ts b/open-sse/translator/request/claude-to-gemini.ts index a75d6053a8..a2ddf9ace6 100644 --- a/open-sse/translator/request/claude-to-gemini.ts +++ b/open-sse/translator/request/claude-to-gemini.ts @@ -9,7 +9,7 @@ import { DEFAULT_THINKING_GEMINI_SIGNATURE } from "../../config/defaultThinkingS * skipping the OpenAI hub intermediate step. */ export function claudeToGeminiRequest(model, body, stream) { - const result = { + const result: Record = { model: model, contents: [], generationConfig: {}, @@ -18,19 +18,15 @@ export function claudeToGeminiRequest(model, body, stream) { // ── Generation config ────────────────────────────────────────── if (body.temperature !== undefined) { - // @ts-ignore result.generationConfig.temperature = body.temperature; } if (body.top_p !== undefined) { - // @ts-ignore result.generationConfig.topP = body.top_p; } if (body.top_k !== undefined) { - // @ts-ignore result.generationConfig.topK = body.top_k; } if (body.max_tokens !== undefined) { - // @ts-ignore result.generationConfig.maxOutputTokens = body.max_tokens; } @@ -43,7 +39,6 @@ export function claudeToGeminiRequest(model, body, stream) { systemText = String(body.system); } if (systemText) { - // @ts-ignore result.systemInstruction = { role: "user", parts: [{ text: systemText }], @@ -157,14 +152,12 @@ export function claudeToGeminiRequest(model, body, stream) { } } if (functionDeclarations.length > 0) { - // @ts-ignore result.tools = [{ functionDeclarations }]; } } // ── Thinking config ──────────────────────────────────────────── if (body.thinking?.type === "enabled" && body.thinking.budget_tokens) { - // @ts-ignore result.generationConfig.thinkingConfig = { thinkingBudget: body.thinking.budget_tokens, include_thoughts: true, diff --git a/open-sse/translator/request/claude-to-openai.ts b/open-sse/translator/request/claude-to-openai.ts index 307d78f87d..65d5be281b 100644 --- a/open-sse/translator/request/claude-to-openai.ts +++ b/open-sse/translator/request/claude-to-openai.ts @@ -4,7 +4,7 @@ import { adjustMaxTokens } from "../helpers/maxTokensHelper.js"; // Convert Claude request to OpenAI format export function claudeToOpenAIRequest(model, body, stream) { - const result = { + const result: Record = { model: model, messages: [], stream: stream, @@ -12,13 +12,11 @@ export function claudeToOpenAIRequest(model, body, stream) { // Max tokens if (body.max_tokens) { - // @ts-ignore result.max_tokens = adjustMaxTokens(body); } // Temperature if (body.temperature !== undefined) { - // @ts-ignore result.temperature = body.temperature; } @@ -57,7 +55,6 @@ export function claudeToOpenAIRequest(model, body, stream) { // Tools if (body.tools && Array.isArray(body.tools)) { - // @ts-ignore result.tools = body.tools.map((tool) => ({ type: "function", function: { @@ -70,7 +67,6 @@ export function claudeToOpenAIRequest(model, body, stream) { // Tool choice if (body.tool_choice) { - // @ts-ignore result.tool_choice = convertToolChoice(body.tool_choice); } diff --git a/open-sse/translator/request/gemini-to-openai.ts b/open-sse/translator/request/gemini-to-openai.ts index 905e6352d1..13a46d0c56 100644 --- a/open-sse/translator/request/gemini-to-openai.ts +++ b/open-sse/translator/request/gemini-to-openai.ts @@ -4,7 +4,7 @@ import { adjustMaxTokens } from "../helpers/maxTokensHelper.js"; // Convert Gemini request to OpenAI format export function geminiToOpenAIRequest(model, body, stream) { - const result = { + const result: Record = { model: model, messages: [], stream: stream, @@ -15,15 +15,12 @@ export function geminiToOpenAIRequest(model, body, stream) { const config = body.generationConfig; if (config.maxOutputTokens) { const tempBody = { max_tokens: config.maxOutputTokens, tools: body.tools }; - // @ts-ignore result.max_tokens = adjustMaxTokens(tempBody); } if (config.temperature !== undefined) { - // @ts-ignore result.temperature = config.temperature; } if (config.topP !== undefined) { - // @ts-ignore result.top_p = config.topP; } } @@ -51,12 +48,10 @@ export function geminiToOpenAIRequest(model, body, stream) { // Tools if (body.tools && Array.isArray(body.tools)) { - // @ts-ignore result.tools = []; for (const tool of body.tools) { if (tool.functionDeclarations) { for (const func of tool.functionDeclarations) { - // @ts-ignore result.tools.push({ type: "function", function: { diff --git a/open-sse/translator/request/openai-responses.ts b/open-sse/translator/request/openai-responses.ts index bef28d0b2a..1ac99d36ec 100644 --- a/open-sse/translator/request/openai-responses.ts +++ b/open-sse/translator/request/openai-responses.ts @@ -21,10 +21,8 @@ export function openaiResponsesToOpenAIRequest(model, body, stream, credentials) const error = new Error( `Unsupported Responses API feature: ${tool.type} tool type is not supported by omniroute` ); - // @ts-ignore — custom error property - error.statusCode = 400; - // @ts-ignore — custom error property - error.errorType = "unsupported_feature"; + (error as any).statusCode = 400; + (error as any).errorType = "unsupported_feature"; throw error; } } @@ -33,14 +31,12 @@ export function openaiResponsesToOpenAIRequest(model, body, stream, credentials) const error = new Error( "Unsupported Responses API feature: background mode is not supported by omniroute" ); - // @ts-ignore — custom error property - error.statusCode = 400; - // @ts-ignore — custom error property - error.errorType = "unsupported_feature"; + (error as any).statusCode = 400; + (error as any).errorType = "unsupported_feature"; throw error; } - const result = { ...body }; + const result: Record = { ...body }; result.messages = []; // Convert instructions to system message @@ -163,7 +159,7 @@ export function openaiResponsesToOpenAIRequest(model, body, stream, credentials) * Convert OpenAI Chat Completions to OpenAI Responses API format */ export function openaiToOpenAIResponsesRequest(model, body, stream, credentials) { - const result = { + const result: Record = { model, input: [], stream: true, @@ -178,7 +174,6 @@ export function openaiToOpenAIResponsesRequest(model, body, stream, credentials) if (msg.role === "system") { // Use first system message as instructions if (!hasSystemMessage) { - // @ts-ignore result.instructions = typeof msg.content === "string" ? msg.content : ""; hasSystemMessage = true; } @@ -280,13 +275,11 @@ export function openaiToOpenAIResponsesRequest(model, body, stream, credentials) // If no system message, leave instructions empty if (!hasSystemMessage) { - // @ts-ignore result.instructions = ""; } // Convert tools format if (body.tools && Array.isArray(body.tools)) { - // @ts-ignore result.tools = body.tools.map((tool) => { if (tool.type === "function") { return { @@ -302,11 +295,8 @@ export function openaiToOpenAIResponsesRequest(model, body, stream, credentials) } // Pass through other relevant fields - // @ts-ignore if (body.temperature !== undefined) result.temperature = body.temperature; - // @ts-ignore if (body.max_tokens !== undefined) result.max_tokens = body.max_tokens; - // @ts-ignore if (body.top_p !== undefined) result.top_p = body.top_p; return result; diff --git a/open-sse/translator/request/openai-to-claude.ts b/open-sse/translator/request/openai-to-claude.ts index c07759e173..62aac8e6f8 100644 --- a/open-sse/translator/request/openai-to-claude.ts +++ b/open-sse/translator/request/openai-to-claude.ts @@ -11,7 +11,7 @@ const CLAUDE_OAUTH_TOOL_PREFIX = "proxy_"; export function openaiToClaudeRequest(model, body, stream) { // Tool name mapping for Claude OAuth (capitalizedName → originalName) const toolNameMap = new Map(); - const result = { + const result: Record = { model: model, max_tokens: adjustMaxTokens(body), stream: stream, @@ -19,12 +19,10 @@ export function openaiToClaudeRequest(model, body, stream) { // Temperature if (body.temperature !== undefined) { - // @ts-ignore result.temperature = body.temperature; } // Messages - // @ts-ignore result.messages = []; const systemParts = []; @@ -48,7 +46,6 @@ export function openaiToClaudeRequest(model, body, stream) { const flushCurrentMessage = () => { if (currentRole && currentParts.length > 0) { - // @ts-ignore result.messages.push({ role: currentRole, content: currentParts }); currentParts = []; } @@ -68,7 +65,6 @@ export function openaiToClaudeRequest(model, body, stream) { flushCurrentMessage(); if (toolResultBlocks.length > 0) { - // @ts-ignore result.messages.push({ role: "user", content: toolResultBlocks }); } @@ -94,9 +90,7 @@ export function openaiToClaudeRequest(model, body, stream) { flushCurrentMessage(); // Add cache_control to last assistant message - // @ts-ignore for (let i = result.messages.length - 1; i >= 0; i--) { - // @ts-ignore const message = result.messages[i]; if ( message.role === "assistant" && @@ -117,19 +111,16 @@ export function openaiToClaudeRequest(model, body, stream) { if (systemParts.length > 0) { const systemText = systemParts.join("\n"); - // @ts-ignore result.system = [ claudeCodePrompt, { type: "text", text: systemText, cache_control: { type: "ephemeral", ttl: "1h" } }, ]; } else { - // @ts-ignore result.system = [claudeCodePrompt]; } // Tools - convert from OpenAI format to Claude format with prefix for OAuth if (body.tools && Array.isArray(body.tools)) { - // @ts-ignore result.tools = body.tools.map((tool) => { const toolData = tool.type === "function" && tool.function ? tool.function : tool; const originalName = toolData.name; @@ -148,22 +139,18 @@ export function openaiToClaudeRequest(model, body, stream) { }; }); - // @ts-ignore if (result.tools.length > 0) { - // @ts-ignore result.tools[result.tools.length - 1].cache_control = { type: "ephemeral", ttl: "1h" }; } } // Tool choice if (body.tool_choice) { - // @ts-ignore result.tool_choice = convertOpenAIToolChoice(body.tool_choice); } // Thinking configuration if (body.thinking) { - // @ts-ignore result.thinking = { type: body.thinking.type || "enabled", ...(body.thinking.budget_tokens && { budget_tokens: body.thinking.budget_tokens }), @@ -173,7 +160,6 @@ export function openaiToClaudeRequest(model, body, stream) { // Attach toolNameMap to result for response translation if (toolNameMap.size > 0) { - // @ts-ignore result._toolNameMap = toolNameMap; } @@ -310,23 +296,17 @@ function openaiToClaudeRequestForAntigravity(model, body, stream) { const result = openaiToClaudeRequest(model, body, stream); // Remove Claude Code system prompt, keep only user's system messages - // @ts-ignore if (result.system && Array.isArray(result.system)) { - // @ts-ignore result.system = result.system.filter( (block) => !block.text || !block.text.includes("You are Claude Code") ); - // @ts-ignore if (result.system.length === 0) { - // @ts-ignore delete result.system; } } // Strip prefix from tool names for Antigravity (doesn't use Claude OAuth) - // @ts-ignore if (result.tools && Array.isArray(result.tools)) { - // @ts-ignore result.tools = result.tools.map((tool) => { if (tool.name && tool.name.startsWith(CLAUDE_OAUTH_TOOL_PREFIX)) { return { @@ -339,9 +319,7 @@ function openaiToClaudeRequestForAntigravity(model, body, stream) { } // Strip prefix from tool_use in messages - // @ts-ignore if (result.messages && Array.isArray(result.messages)) { - // @ts-ignore result.messages = result.messages.map((msg) => { if (!msg.content || !Array.isArray(msg.content)) { return msg; diff --git a/open-sse/translator/request/openai-to-gemini.ts b/open-sse/translator/request/openai-to-gemini.ts index 4c3d2e6c1c..d9dc479d23 100644 --- a/open-sse/translator/request/openai-to-gemini.ts +++ b/open-sse/translator/request/openai-to-gemini.ts @@ -21,7 +21,7 @@ import { // Core: Convert OpenAI request to Gemini format (base for all variants) function openaiToGeminiBase(model, body, stream) { - const result = { + const result: Record = { model: model, contents: [], generationConfig: {}, @@ -30,19 +30,15 @@ function openaiToGeminiBase(model, body, stream) { // Generation config if (body.temperature !== undefined) { - // @ts-ignore result.generationConfig.temperature = body.temperature; } if (body.top_p !== undefined) { - // @ts-ignore result.generationConfig.topP = body.top_p; } if (body.top_k !== undefined) { - // @ts-ignore result.generationConfig.topK = body.top_k; } if (body.max_tokens !== undefined) { - // @ts-ignore result.generationConfig.maxOutputTokens = body.max_tokens; } @@ -78,7 +74,6 @@ function openaiToGeminiBase(model, body, stream) { const content = msg.content; if (role === "system" && body.messages.length > 1) { - // @ts-ignore result.systemInstruction = { role: "user", parts: [{ text: typeof content === "string" ? content : extractTextContent(content) }], @@ -200,7 +195,6 @@ function openaiToGeminiBase(model, body, stream) { } if (functionDeclarations.length > 0) { - // @ts-ignore result.tools = [{ functionDeclarations }]; } } @@ -222,7 +216,6 @@ export function openaiToGeminiCLIRequest(model, body, stream) { if (body.reasoning_effort) { const budgetMap = { low: 1024, medium: 8192, high: 32768 }; const budget = budgetMap[body.reasoning_effort] || 8192; - // @ts-ignore gemini.generationConfig.thinkingConfig = { thinkingBudget: budget, include_thoughts: true, @@ -231,7 +224,6 @@ export function openaiToGeminiCLIRequest(model, body, stream) { // Thinking config from Claude format if (body.thinking?.type === "enabled" && body.thinking.budget_tokens) { - // @ts-ignore gemini.generationConfig.thinkingConfig = { thinkingBudget: body.thinking.budget_tokens, include_thoughts: true, @@ -239,9 +231,7 @@ export function openaiToGeminiCLIRequest(model, body, stream) { } // Clean schema for tools - // @ts-ignore if (gemini.tools?.[0]?.functionDeclarations) { - // @ts-ignore for (const fn of gemini.tools[0].functionDeclarations) { if (fn.parameters) { const cleanedSchema = cleanJSONSchemaForAntigravity(fn.parameters); @@ -263,7 +253,7 @@ export function openaiToGeminiCLIRequest(model, body, stream) { function wrapInCloudCodeEnvelope(model, geminiCLI, credentials = null, isAntigravity = false) { const projectId = credentials?.projectId || generateProjectId(); - const envelope = { + const envelope: Record = { project: projectId, model: model, userAgent: isAntigravity ? "antigravity" : "gemini-cli", @@ -279,11 +269,10 @@ function wrapInCloudCodeEnvelope(model, geminiCLI, credentials = null, isAntigra // Antigravity specific fields if (isAntigravity) { - // @ts-ignore envelope.requestType = "agent"; // Inject required default system prompt for Antigravity - const defaultPart = { text: ANTIGRAVITY_DEFAULT_SYSTEM }; + const defaultPart: Record = { text: ANTIGRAVITY_DEFAULT_SYSTEM }; if (envelope.request.systemInstruction?.parts) { envelope.request.systemInstruction.parts.unshift(defaultPart); } else { @@ -292,14 +281,12 @@ function wrapInCloudCodeEnvelope(model, geminiCLI, credentials = null, isAntigra // Add toolConfig for Antigravity if (geminiCLI.tools?.length > 0) { - // @ts-ignore envelope.request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" }, }; } } else { // Keep safetySettings for Gemini CLI - // @ts-ignore envelope.request.safetySettings = geminiCLI.safetySettings; } @@ -310,7 +297,7 @@ function wrapInCloudCodeEnvelope(model, geminiCLI, credentials = null, isAntigra function wrapInCloudCodeEnvelopeForClaude(model, claudeRequest, credentials = null) { const projectId = credentials?.projectId || generateProjectId(); - const envelope = { + const envelope: Record = { project: projectId, model: model, userAgent: "antigravity", @@ -386,9 +373,7 @@ function wrapInCloudCodeEnvelopeForClaude(model, claudeRequest, credentials = nu } } if (functionDeclarations.length > 0) { - // @ts-ignore envelope.request.tools = [{ functionDeclarations }]; - // @ts-ignore envelope.request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" }, }; @@ -409,7 +394,6 @@ function wrapInCloudCodeEnvelopeForClaude(model, claudeRequest, credentials = nu } } - // @ts-ignore envelope.request.systemInstruction = { role: "user", parts: systemParts }; return envelope; diff --git a/open-sse/translator/request/openai-to-kiro.ts b/open-sse/translator/request/openai-to-kiro.ts index 866bfd85f9..7bb5e6c43e 100644 --- a/open-sse/translator/request/openai-to-kiro.ts +++ b/open-sse/translator/request/openai-to-kiro.ts @@ -22,7 +22,7 @@ function convertMessages(messages, tools, model) { const flushPending = () => { if (currentRole === "user") { const content = pendingUserContent.join("\n\n").trim() || "continue"; - const userMsg = { + const userMsg: Record = { userInputMessage: { content: content, modelId: "", @@ -30,7 +30,6 @@ function convertMessages(messages, tools, model) { }; if (pendingToolResults.length > 0) { - // @ts-ignore userMsg.userInputMessage.userInputMessageContext = { toolResults: pendingToolResults, }; @@ -38,12 +37,9 @@ function convertMessages(messages, tools, model) { // Add tools to first user message if (tools && tools.length > 0 && history.length === 0) { - // @ts-ignore if (!userMsg.userInputMessage.userInputMessageContext) { - // @ts-ignore userMsg.userInputMessage.userInputMessageContext = {}; } - // @ts-ignore userMsg.userInputMessage.userInputMessageContext.tools = tools.map((t) => { const name = t.function?.name || t.name; let description = t.function?.description || t.description || ""; @@ -259,7 +255,7 @@ export function buildKiroPayload(model, body, stream, credentials) { const timestamp = new Date().toISOString(); finalContent = `[Context: Current time is ${timestamp}]\n\n${finalContent}`; - const payload = { + const payload: Record = { conversationState: { chatTriggerType: "MANUAL", conversationId: uuidv4(), @@ -278,18 +274,13 @@ export function buildKiroPayload(model, body, stream, credentials) { }; if (profileArn) { - // @ts-ignore payload.profileArn = profileArn; } if (maxTokens || temperature !== undefined || topP !== undefined) { - // @ts-ignore payload.inferenceConfig = {}; - // @ts-ignore if (maxTokens) payload.inferenceConfig.maxTokens = maxTokens; - // @ts-ignore if (temperature !== undefined) payload.inferenceConfig.temperature = temperature; - // @ts-ignore if (topP !== undefined) payload.inferenceConfig.topP = topP; } diff --git a/open-sse/translator/response/claude-to-openai.ts b/open-sse/translator/response/claude-to-openai.ts index 94adfb4a9a..47cb022f70 100644 --- a/open-sse/translator/response/claude-to-openai.ts +++ b/open-sse/translator/response/claude-to-openai.ts @@ -133,7 +133,7 @@ export function claudeToOpenAIResponse(chunk, state) { if (chunk.delta?.stop_reason) { state.finishReason = convertStopReason(chunk.delta.stop_reason); - const finalChunk = { + const finalChunk: Record = { id: `chatcmpl-${state.messageId}`, object: "chat.completion.chunk", created: Math.floor(Date.now() / 1000), @@ -161,7 +161,6 @@ export function claudeToOpenAIResponse(chunk, state) { const completionTokens = outputTokens; const totalTokens = promptTokens + completionTokens; - // @ts-ignore finalChunk.usage = { prompt_tokens: promptTokens, completion_tokens: completionTokens, @@ -170,14 +169,11 @@ export function claudeToOpenAIResponse(chunk, state) { // Add prompt_tokens_details if cached tokens exist if (cachedTokens > 0 || cacheCreationTokens > 0) { - // @ts-ignore finalChunk.usage.prompt_tokens_details = {}; if (cachedTokens > 0) { - // @ts-ignore finalChunk.usage.prompt_tokens_details.cached_tokens = cachedTokens; } if (cacheCreationTokens > 0) { - // @ts-ignore finalChunk.usage.prompt_tokens_details.cache_creation_tokens = cacheCreationTokens; } } diff --git a/open-sse/translator/response/gemini-to-openai.ts b/open-sse/translator/response/gemini-to-openai.ts index b09dfef4b8..8e57ffefc8 100644 --- a/open-sse/translator/response/gemini-to-openai.ts +++ b/open-sse/translator/response/gemini-to-openai.ts @@ -226,7 +226,7 @@ export function geminiToOpenAIResponse(chunk, state) { finishReason = "tool_calls"; } - const finalChunk = { + const finalChunk: Record = { id: `chatcmpl-${state.messageId}`, object: "chat.completion.chunk", created: Math.floor(Date.now() / 1000), @@ -242,7 +242,6 @@ export function geminiToOpenAIResponse(chunk, state) { // Include usage in final chunk for downstream translators if (state.usage) { - // @ts-ignore finalChunk.usage = state.usage; } diff --git a/open-sse/translator/response/kiro-to-openai.ts b/open-sse/translator/response/kiro-to-openai.ts index 9541035002..969595b01b 100644 --- a/open-sse/translator/response/kiro-to-openai.ts +++ b/open-sse/translator/response/kiro-to-openai.ts @@ -155,7 +155,7 @@ export function convertKiroToOpenAI(chunk, state) { if (eventType === "messageStopEvent" || eventType === "done" || data.messageStopEvent) { state.finishReason = "stop"; // Mark for usage injection in stream.js - const openaiChunk = { + const openaiChunk: Record = { id: state.responseId, object: "chat.completion.chunk", created: state.created, @@ -171,7 +171,6 @@ export function convertKiroToOpenAI(chunk, state) { // Include usage in final chunk if available if (state.usage && typeof state.usage === "object") { - // @ts-ignore openaiChunk.usage = state.usage; } diff --git a/open-sse/translator/response/openai-responses.ts b/open-sse/translator/response/openai-responses.ts index 2aa4dbe716..417a133bd9 100644 --- a/open-sse/translator/response/openai-responses.ts +++ b/open-sse/translator/response/openai-responses.ts @@ -519,7 +519,7 @@ export function openaiResponsesToOpenAIResponse(chunk, state) { state.finishReasonSent = true; state.finishReason = "stop"; // Mark for usage injection in stream.js - const finalChunk = { + const finalChunk: Record = { id: state.chatId, object: "chat.completion.chunk", created: state.created, @@ -535,7 +535,6 @@ export function openaiResponsesToOpenAIResponse(chunk, state) { // Include usage in final chunk if available if (state.usage && typeof state.usage === "object") { - // @ts-ignore finalChunk.usage = state.usage; } diff --git a/open-sse/translator/response/openai-to-antigravity.ts b/open-sse/translator/response/openai-to-antigravity.ts index 70cc673ca2..82f17bedac 100644 --- a/open-sse/translator/response/openai-to-antigravity.ts +++ b/open-sse/translator/response/openai-to-antigravity.ts @@ -81,7 +81,7 @@ export function openaiToAntigravityResponse(chunk, state) { } // Build candidate - const candidate = { content: { role: "model", parts } }; + const candidate: Record = { content: { role: "model", parts } }; // Finish reason mapping if (finishReason) { @@ -91,12 +91,11 @@ export function openaiToAntigravityResponse(chunk, state) { tool_calls: "STOP", content_filter: "SAFETY", }; - // @ts-ignore candidate.finishReason = reasonMap[finishReason] || "STOP"; } // Build response - const response = { + const response: Record = { candidates: [candidate], modelVersion: state._modelVersion, responseId: state._responseId, @@ -105,18 +104,15 @@ export function openaiToAntigravityResponse(chunk, state) { // Usage metadata const usage = chunk.usage || state._usage; if (usage) { - // @ts-ignore response.usageMetadata = { promptTokenCount: usage.prompt_tokens || 0, candidatesTokenCount: usage.completion_tokens || 0, totalTokenCount: usage.total_tokens || 0, }; if (usage.completion_tokens_details?.reasoning_tokens) { - // @ts-ignore response.usageMetadata.thoughtsTokenCount = usage.completion_tokens_details.reasoning_tokens; } if (usage.prompt_tokens_details?.cached_tokens) { - // @ts-ignore response.usageMetadata.cachedContentTokenCount = usage.prompt_tokens_details.cached_tokens; } } diff --git a/open-sse/utils/error.ts b/open-sse/utils/error.ts index 479cd288d4..0787c0face 100644 --- a/open-sse/utils/error.ts +++ b/open-sse/utils/error.ts @@ -144,7 +144,6 @@ export function createErrorResult(statusCode: number, message: string, retryAfte result.retryAfterMs = retryAfterMs; } - // @ts-ignore - boolean is assignable to false at runtime return result; } @@ -156,7 +155,7 @@ export function createErrorResult(statusCode: number, message: string, retryAfte * @param {string} retryAfterHuman - Human-readable retry info e.g. "reset after 30s" * @returns {Response} */ -export function unavailableResponse(statusCode, message, retryAfter, retryAfterHuman) { +export function unavailableResponse(statusCode, message, retryAfter?: any, retryAfterHuman?: any) { const retryAfterSec = Math.max( Math.ceil((new Date(retryAfter).getTime() - Date.now()) / 1000), 1 @@ -180,7 +179,6 @@ export function unavailableResponse(statusCode, message, retryAfter, retryAfterH * @returns {string} Formatted error message */ export function formatProviderError(error, provider, model, statusCode) { - // @ts-ignore - Error may have custom 'code' property const code = statusCode || error.code || "FETCH_FAILED"; const message = error.message || "Unknown error"; return `[${code}]: ${message}`; diff --git a/open-sse/utils/proxyDispatcher.ts b/open-sse/utils/proxyDispatcher.ts index c6c0ef70c1..e82b279e73 100644 --- a/open-sse/utils/proxyDispatcher.ts +++ b/open-sse/utils/proxyDispatcher.ts @@ -119,8 +119,7 @@ export function createProxyDispatcher(proxyUrl) { }; if (parsed.username) socksOptions.userId = decodeURIComponent(parsed.username); if (parsed.password) socksOptions.password = decodeURIComponent(parsed.password); - // @ts-ignore - socksOptions conforms to SocksProxies at runtime - dispatcher = socksDispatcher(socksOptions); + dispatcher = socksDispatcher(socksOptions as any); } else { dispatcher = new ProxyAgent(normalizedUrl); } diff --git a/open-sse/utils/stream.ts b/open-sse/utils/stream.ts index 3788f1c926..7e910b5c5a 100644 --- a/open-sse/utils/stream.ts +++ b/open-sse/utils/stream.ts @@ -233,10 +233,8 @@ export function createSSEStream(options: any = {}) { const translated = translateResponse(targetFormat, sourceFormat, parsed, state); // Log OpenAI intermediate chunks (if available) - // @ts-ignore - _openaiIntermediate is a custom property on translated arrays - if (translated?._openaiIntermediate) { - // @ts-ignore - for (const item of translated._openaiIntermediate) { + if ((translated as any)?._openaiIntermediate) { + for (const item of (translated as any)._openaiIntermediate) { const openaiOutput = formatSSE(item, FORMATS.OPENAI); reqLogger?.appendOpenAIChunk?.(openaiOutput); } @@ -331,10 +329,8 @@ export function createSSEStream(options: any = {}) { const translated = translateResponse(targetFormat, sourceFormat, parsed, state); // Log OpenAI intermediate chunks - // @ts-ignore - _openaiIntermediate is a custom property - if (translated?._openaiIntermediate) { - // @ts-ignore - for (const item of translated._openaiIntermediate) { + if ((translated as any)?._openaiIntermediate) { + for (const item of (translated as any)._openaiIntermediate) { const openaiOutput = formatSSE(item, FORMATS.OPENAI); reqLogger?.appendOpenAIChunk?.(openaiOutput); } @@ -354,10 +350,8 @@ export function createSSEStream(options: any = {}) { const flushed = translateResponse(targetFormat, sourceFormat, null, state); // Log OpenAI intermediate chunks for flushed events - // @ts-ignore - _openaiIntermediate is a custom property - if (flushed?._openaiIntermediate) { - // @ts-ignore - for (const item of flushed._openaiIntermediate) { + if ((flushed as any)?._openaiIntermediate) { + for (const item of (flushed as any)._openaiIntermediate) { const openaiOutput = formatSSE(item, FORMATS.OPENAI); reqLogger?.appendOpenAIChunk?.(openaiOutput); } From c164ab877fa4aaa4c292b0d5589bd81f00d7b03a Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Tue, 17 Feb 2026 08:39:16 -0300 Subject: [PATCH 4/4] chore: bump version to 0.8.5 - Update package.json version to 0.8.5 - Update package-lock.json version to 0.8.5 - Update version references in docs/new-features --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4f8dbddad..f128d8b998 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute", - "version": "0.8.0", + "version": "0.8.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute", - "version": "0.8.0", + "version": "0.8.5", "license": "MIT", "workspaces": [ "open-sse" diff --git a/package.json b/package.json index 9bb0cfff30..f3379e97fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omniroute", - "version": "0.8.0", + "version": "0.8.5", "description": "Smart AI Router with auto fallback — route to FREE & cheap models, zero downtime. Works with Cursor, Cline, Claude Desktop, Codex, and any OpenAI-compatible tool.", "type": "module", "bin": {