@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
127 lines (126 loc) • 4.83 kB
TypeScript
/**
* Proxy Translation Engine
*
* Shared translation logic used by both Claude and OpenAI proxy routes.
* Both formats follow the same pipeline:
* 1. Parse request (format-specific, done by the caller)
* 2. Loop through fallback attempts calling ctx.neurolink.stream()
* 3. Serialize response (format-specific, via serializer/response builder)
*
* This module exports the helpers that were previously duplicated between
* claudeProxyRoutes.ts and openaiProxyRoutes.ts, plus unified stream and
* JSON handlers that accept a format discriminator.
*/
import type { ProxyTracer } from "./proxyTracer.js";
import type { ParsedClaudeRequest, ParsedGeminiRequest, ParsedOpenAIRequest, ProxyFormat, ProxyTranslationAttempt, ServerContext } from "../types/index.js";
/**
* Extract text content from a stream chunk (handles various chunk formats).
*/
export declare function extractText(chunk: unknown): string | null;
/** Extract tool call arguments from various shapes. */
export declare function extractToolArgs(toolCall: unknown): unknown;
/** Check if there's meaningful output from translation. */
export declare function hasTranslatedOutput(collectedText: string, toolCalls: unknown[] | undefined): boolean;
/**
* Normalize usage from various AI SDK / NeuroLink shapes.
*
* Handles:
* - AI SDK v6: inputTokens / outputTokens
* - AI SDK v4: promptTokens / completionTokens
* - NeuroLink internal: input / output
*/
export declare function extractUsageFromStreamResult(usage: unknown): {
input: number;
output: number;
total: number;
};
/**
* Detect which proxy format a request is using based on path and headers.
*/
export declare function detectProxyFormat(path: string, headers: Record<string, string>): ProxyFormat;
/**
* Build options for ctx.neurolink.stream() from a parsed request
* and an optional provider/model override.
*
* Works for ParsedClaudeRequest, ParsedOpenAIRequest and
* ParsedGeminiRequest. The differences are Claude-specific fields (topK,
* thinkingConfig), safely absent on OpenAI/Gemini parsed requests, and
* toolChoice/toolChoiceName, absent on Gemini parsed requests — Gemini's
* parser always emits tools: {} (see geminiFormat.ts's parseGeminiRequest),
* so toolNames.length is always 0 below and disableTools is set instead.
*/
export declare function buildTranslationOptions(parsed: ParsedClaudeRequest | ParsedOpenAIRequest | ParsedGeminiRequest, overrides?: {
provider?: string;
model?: string;
}): Record<string, unknown>;
/** Demand-driven serialization; a slow reader cannot grow an unbounded queue. */
export declare function handleTranslatedStreamRequest(args: {
ctx: ServerContext;
format: ProxyFormat;
requestModel: string;
parsed: ParsedClaudeRequest | ParsedOpenAIRequest | ParsedGeminiRequest;
attempts: ProxyTranslationAttempt[];
tracer?: ProxyTracer;
requestStartTime: number;
/** Preserve outer fallback choice until first upstream output exists. */
prefetchFirstOutput?: boolean;
options?: Parameters<ServerContext["neurolink"]["stream"]>[0];
attemptTimeoutMs?: number;
}): Promise<Response>;
export declare function handleTranslatedJsonRequest(args: {
ctx: ServerContext;
format: ProxyFormat;
requestModel: string;
parsed: ParsedClaudeRequest | ParsedOpenAIRequest | ParsedGeminiRequest;
attempts: ProxyTranslationAttempt[];
tracer?: ProxyTracer;
requestStartTime: number;
terminalFailureStatus?: number;
deferFinalOnError?: boolean;
options?: Parameters<ServerContext["neurolink"]["stream"]>[0];
attemptTimeoutMs?: number;
}): Promise<unknown>;
/**
* Build the /v1/models response in OpenAI list format.
* Used by both Claude and OpenAI proxy routes.
*/
export declare function buildModelsListResponse(modelRouter?: {
getModelMappings?: () => Array<{
from: string;
}>;
getPassthroughModels?: () => string[];
}): {
object: string;
data: Array<{
id: string;
object: string;
created: number;
owned_by: string;
}>;
};
/**
* Build an Anthropic-shaped `/v1/models` list response.
*
* Used by the Claude-compatible route so Anthropic SDK consumers receive
* the schema they expect:
* { data: [{type, id, display_name, created_at}], first_id, last_id, has_more }
*
* The OpenAI route continues to use {@link buildModelsListResponse} for the
* OpenAI list shape.
*/
export declare function buildAnthropicModelsListResponse(modelRouter?: {
getModelMappings?: () => Array<{
from?: string;
}>;
getPassthroughModels?: () => string[];
}): {
data: Array<{
type: "model";
id: string;
display_name: string;
created_at: string;
}>;
first_id: string | null;
last_id: string | null;
has_more: boolean;
};