refactor(open-sse): phase 7 — zero @ts-ignore, zero TSC errors

- Remove ALL 231 @ts-ignore annotations (231 → 0)
- Fix 237 TypeScript errors with proper typings:
  - Type 30+ variable declarations as Record<string, any>
  - 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
This commit is contained in:
diegosouzapw
2026-02-17 08:31:52 -03:00
parent c9f9892095
commit c9a26da798
38 changed files with 72 additions and 252 deletions

View File

@@ -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 };

View File

@@ -125,7 +125,7 @@ export class KiroExecutor extends BaseExecutor {
const content = event.payload.content;
state.totalContentLength += content.length;
const chunk = {
const chunk: Record<string, any> = {
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<string, any> = {
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<string, any> = {
id: responseId,
object: "chat.completion.chunk",
created,
@@ -329,7 +329,7 @@ export class KiroExecutor extends BaseExecutor {
};
}
const finishChunk = {
const finishChunk: Record<string, any> = {
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;
}

View File

@@ -52,15 +52,13 @@ export async function handleEmbedding({ body, credentials, log }) {
}
// Build upstream request
const upstreamBody = {
const upstreamBody: Record<string, any> = {
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

View File

@@ -232,21 +232,16 @@ async function handleOpenAIImageGeneration({
};
// Build upstream request (OpenAI-compatible format)
const upstreamBody = {
const upstreamBody: Record<string, any> = {
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

View File

@@ -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<string, any> = {
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<string, any> = {
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<string, any> = {
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,

View File

@@ -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;

View File

@@ -51,7 +51,7 @@ export function parseSSEToOpenAIResponse(rawSSE, fallbackModel) {
message.reasoning_content = reasoningParts.join("");
}
const result = {
const result: Record<string, any> = {
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;
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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)"

View File

@@ -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 || {};

View File

@@ -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<string, any> = {};
for (const [name] of metrics) {
result[name] = getComboMetrics(name);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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<string, any> = { 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<string, any> = {};
for (const [key, limiter] of limiters) {
const counts = limiter.counts();
result[key] = {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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., "<antThinking>")
* @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 = [];

View File

@@ -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<string, any> = {};
// 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,
};
}

View File

@@ -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);

View File

@@ -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<string, any> = {};
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];
}

View File

@@ -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;

View File

@@ -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<string, any> = {
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<string, any> = { 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;

View File

@@ -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<string, any> = {
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,

View File

@@ -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<string, any> = {
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);
}

View File

@@ -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<string, any> = {
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: {

View File

@@ -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<string, any> = { ...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<string, any> = {
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;

View File

@@ -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<string, any> = {
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;

View File

@@ -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<string, any> = {
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<string, any> = {
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<string, any> = { 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<string, any> = {
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;

View File

@@ -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<string, any> = {
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<string, any> = {
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;
}

View File

@@ -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<string, any> = {
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;
}
}

View File

@@ -226,7 +226,7 @@ export function geminiToOpenAIResponse(chunk, state) {
finishReason = "tool_calls";
}
const finalChunk = {
const finalChunk: Record<string, any> = {
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;
}

View File

@@ -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<string, any> = {
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;
}

View File

@@ -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<string, any> = {
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;
}

View File

@@ -81,7 +81,7 @@ export function openaiToAntigravityResponse(chunk, state) {
}
// Build candidate
const candidate = { content: { role: "model", parts } };
const candidate: Record<string, any> = { 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<string, any> = {
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;
}
}

View File

@@ -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}`;

View File

@@ -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);
}

View File

@@ -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);
}