@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
90 lines (89 loc) • 4.17 kB
TypeScript
/**
* Gemini-Compatible Proxy Routes
*
* Exposes the Google `generateContent` / `streamGenerateContent` endpoints the
* Gemini CLI calls when pointed at this proxy via `GOOGLE_GEMINI_BASE_URL`.
* ALL requests are routed through ctx.neurolink.stream() via the shared proxy
* translation engine — no direct HTTP calls to any upstream provider.
*
* This is a thin wrapper that parses the Google wire format and delegates to
* the same translation engine openaiProxyRoutes.ts and claudeProxyRoutes.ts
* use, mirroring that file's validate → log → delegate shape.
*
* An optional ModelRouter can remap incoming model names to different
* provider/model pairs, exactly as it does for the OpenAI-compatible door.
*/
import type { ModelRouterInterface, ParsedGeminiRequest, ProxyRuntimeConfigProvider, RouteGroup } from "../../types/index.js";
/**
* Google bakes the action into the final path segment as `<model>:<action>`
* (`models/gemini-2.5-pro:generateContent`). Hono's router has no way to
* express a literal `:` after a named param — verified directly against the
* `hono` version this repo pins: registering `:model\:generateContent`
* doesn't escape the colon, it becomes *part of the param name*, and the
* resulting param still greedily swallows the whole trailing segment
* (`streamGenerateContent` included) because nothing after the leading `:`
* stops the capture except the next `/`. A `:model{regex}` constraint
* followed by literal text fails outright — the route never matches (404 on
* every request). A bare `:model` segment is therefore the only shape that
* actually matches; it captures `<model>:<action>` whole, and this function
* splits it back apart in the handler instead of in the route table.
*/
/**
* Pull "<model>:<action>" out of the request path.
*
* Read from `ctx.path`, not from a route param. Hono does capture the whole
* `gemini-2.5-pro:generateContent` segment — the colon is not a route
* separator, so one route covers both actions — but the proxy's mount loop
* builds its ServerContext from `path`, `headers`, `query`, `body`, `method`
* and `requestId` only. The captured param never reaches the handler, and
* reading `ctx.params` here would be `undefined` on every request.
*/
declare function splitModelAction(requestPath: string): {
modelId: string;
action: string | undefined;
};
/**
* buildProxyTranslationPlan's classifier expects ParsedClaudeRequest, whose
* `maxTokens` is required. Gemini's is optional (Google omits
* `generationConfig.maxOutputTokens` on plenty of real requests), so the gap
* is bridged the same way the OpenAI door bridges it: fill in a safe default
* and let the (structurally near-identical) rest pass through untouched.
*/
declare function adaptGeminiForTranslationPlan(parsed: ParsedGeminiRequest): {
model: string;
maxTokens: number;
temperature?: number;
topP?: number;
systemPrompt?: string;
stream: boolean;
prompt: string;
images: string[];
conversationMessages: Array<{
role: string;
content: string;
}>;
tools: Record<string, {
description?: string;
inputSchema: unknown;
execute?: (...args: unknown[]) => unknown;
}>;
stopSequences?: string[];
};
/**
* Create Gemini-compatible proxy routes.
*
* Every request flows through ctx.neurolink.stream() — no direct HTTP calls
* to any upstream provider.
*
* @param modelRouter - Optional model router for remapping model names.
* @param basePath - Base path prefix (default: "").
* @param loopbackPort - Unused by this door; kept for parameter-shape parity
* with createOpenAIProxyRoutes (see DEFAULT_LOOPBACK_PORT).
* @returns RouteGroup with Gemini-compatible endpoints.
*/
export declare function createGeminiProxyRoutes(modelRouter?: ModelRouterInterface, basePath?: string, _loopbackPort?: number, runtimeConfigProvider?: ProxyRuntimeConfigProvider): RouteGroup;
export declare const __testHooks: {
splitModelAction: typeof splitModelAction;
adaptGeminiForTranslationPlan: typeof adaptGeminiForTranslationPlan;
};
export {};