@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
113 lines (112 loc) • 5.85 kB
TypeScript
/**
* Native Claude-to-Vertex passthrough.
*
* Claude on Vertex speaks the Anthropic Messages API, so a fallback to it needs
* no translation at all — the client's body goes upstream essentially verbatim
* and the SSE comes back in the shape the client already expects.
*
* This exists because the SDK/translation path cannot carry an agentic turn:
* it runs its own tool loop, and a request whose tools have no executor (every
* proxied request, since the caller executes them) ends with the pending tool
* call discarded and a step-cap apology returned as assistant text. Tools,
* `tool_use`, `tool_result`, `cache_control` and thinking blocks all survive
* here because nothing reshapes them.
*/
import type { GoogleAuth } from "google-auth-library";
import type { VertexAccessTokenProvider, UsageContext, VertexPassthroughTerminal, VertexAnthropicPassthroughRequest, VertexAnthropicPassthroughTarget } from "../types/index.js";
/**
* Translate `output_config` for Vertex.
*
* An effort level Vertex knows passes through; one it does not is mapped onto
* the nearest level it does. A level with no mapping at all loses only the
* `effort` key, never the sibling settings beside it.
*/
export declare function mapVertexOutputConfig(value: unknown): Record<string, unknown> | undefined;
export declare function buildVertexAnthropicPayload(body: Readonly<Record<string, unknown>>, targetModel?: string): Record<string, unknown>;
/**
* Publisher endpoint for a Claude model on Vertex.
*
* Streaming and non-streaming are different verbs on the same resource, so the
* caller's `stream` flag selects the verb rather than changing the body.
*/
export declare function buildVertexAnthropicUrl(target: VertexAnthropicPassthroughTarget): string;
/** Exported only for continuous-test-suite-vertex-anthropic-fallback.ts,
* which proves concurrent callers share one instance. Not part of the
* package's public surface — this module isn't re-exported from index.ts. */
export declare function auth(): Promise<GoogleAuth>;
/** Test-only: isolates the concurrency proof from cache state any earlier
* test in the same process may have left behind. */
export declare function resetAuthCacheForTests(): void;
/**
* Replace the Google credential lookup, for tests only.
*
* Without this seam the two-leg fallback chain cannot be driven end to end.
* The rest of the hop is reachable — `dispatchVertexAnthropicPassthrough`
* calls the global `fetch`, which a test can replace — but the credential
* lookup goes through gaxios, and gaxios resolves its transport to
* `(await import("node-fetch")).default` rather than `globalThis.fetch`. A
* test that swaps the global therefore cannot intercept the token exchange,
* and on a machine with no Application Default Credentials the leg throws
* before it ever reaches the model. That left the one path that bills in real
* currency with no end-to-end coverage at all.
*
* Pass `undefined` to restore the real credential lookup.
*/
export declare function setVertexAccessTokenProviderForTests(provider: VertexAccessTokenProvider | undefined): void;
/**
* Run once more after a short pause when the first attempt hit a transient
* network failure: anything the shared proxy classifier retries, plus a DNS
* blip. One retry absorbs a blip without hiding a real outage: a second
* failure, or any other error, surfaces unchanged.
*/
export declare function withTransientNetworkRetry<T>(run: () => Promise<T>, delayMs?: number): Promise<T>;
/**
* Send one Anthropic-shaped request to Vertex and return the upstream response
* untouched, so the caller can stream its bytes straight to the client.
*/
export declare function dispatchVertexAnthropicPassthrough(request: VertexAnthropicPassthroughRequest): Promise<Response>;
/** Claude models are the only publisher models this passthrough addresses. */
export declare function isVertexAnthropicModel(model: string): boolean;
/**
* Resolve where Vertex traffic is addressed, using the same environment the
* Vertex provider reads so a fallback lands on the project and region the rest
* of the process already uses.
*/
export declare function resolveVertexTarget(): {
projectId: string;
location: string;
} | undefined;
/**
* Run one Claude-on-Vertex fallback attempt and hand back a response the route
* can serve directly.
*
* A non-2xx upstream throws so the caller's attempt loop records the failure
* and moves to the next hop, exactly as the other providers behave.
*/
export declare function executeVertexAnthropicFallback(args: {
body: Readonly<Record<string, unknown>>;
model: string;
signal?: AbortSignal;
/** Fires exactly once on every exit, so the hop is finalized like any other. */
onTerminal?: (terminal: VertexPassthroughTerminal) => void;
}): Promise<Response>;
/**
* Read usage out of a non-streaming Anthropic reply.
*
* `rawPredict` returns a single `{"type":"message","usage":{...}}` object, which
* carries the whole turn's counts at once rather than splitting them across
* `message_start` and `message_delta`.
*/
export declare function readJsonUsage(text: string): UsageContext;
/**
* Forward a stream unchanged while observing its usage events.
*
* The bytes are passed through untouched — parsing happens on a copy of each
* chunk — so the client sees exactly what Vertex sent.
*
* A transform's `flush` only runs on a clean end, which would leave a stream
* error or a client disconnect with no terminal record at all. An explicit
* reader loop is used instead, so `onTerminal` fires exactly once on every
* exit: normal end, upstream failure, and cancellation.
*/
export declare function observeVertexUsage(body: ReadableStream<Uint8Array>, onTerminal: (terminal: VertexPassthroughTerminal) => void): ReadableStream<Uint8Array>;