NeuroLink
The pipe layer for the AI nervous system.
AI intelligence flows as streams — tokens, tool calls, memory, voice, documents. NeuroLink is the vascular layer that carries these streams from where they are generated (LLM providers: the neurons) to where they are needed (connectors: the organs).
import { NeuroLink } from "@juspay/neurolink";
const pipe = new NeuroLink();
// Everything is a stream
const result = await pipe.stream({ input: { text: "Hello" } });
for await (const chunk of result.stream) {
if ("content" in chunk) {
process.stdout.write(chunk.content);
}
}
// Or skip text entirely: a calibrated decision, not a token stream
const decision = await pipe.tryDecide({
// null if no decision provider is set
state: { ticket: "Refund request, $42, first occurrence" },
questions: {
autoApprove: {
type: "boolean",
instructions: "Approve without human review.",
},
},
});
// decision?.answers.autoApprove.probability -> 0.91
→ Docs · → Quick Start · → npm · → Blog
🧠 What is NeuroLink?
NeuroLink is the pipe layer of an AI nervous system. Providers — OpenAI, Anthropic, Google, AWS, Azure, Mistral, local runtimes like Ollama, and dozens more — are the neurons: each generates a different kind of intelligence, at a different cost and latency. NeuroLink is the vascular layer that carries that intelligence, as a stream, to the applications — the organs — that consume it, across three inference types: generate and stream produce text, decide produces a calibrated boolean/choice/score judgment instead. A curated model registry (64 models, 132 aliases) backs metadata, routing, and context-window checks out of the box, and hundreds more models are reachable through aggregator providers — 100+ via LiteLLM, 300+ via OpenRouter.
Extracted from production systems at Juspay, NeuroLink provides a practical, TypeScript-first way to plug any application into that nervous system. Switch which neuron answers a request with a single parameter change — OpenAI, Anthropic, Google, AWS Bedrock, Azure, a local runtime, or any provider you add. decide is the third inference type — a typed, calibrated judgment instead of text — for the model-routing and gating decisions generate/stream were never meant to make, powered by a purpose-built decision model (TypeSafe Jev, Perplexity's hosted Decisions API, Cloudflare's hosted Clef, Subquadratic's hosted SubQ Snap, OpenAI's hosted Decisions API, or the open-weights Laya or XOR) rather than a general-purpose LLM: with Jev, routing decisions land in ~400ms for about $0.00002, instead of a full generation call.
Why NeuroLink? Three genuine inference types, not one dressed up three ways — generate and stream produce text; decide produces a calibrated boolean/choice/score judgment, and which types a provider serves is declared per-provider via inferenceKinds rather than inferred from behavior. Every neuron plugs into the same pipe, including 3 fully local runtimes (Ollama, LM Studio, llama.cpp) with per-request credential overrides, and MCP support covers all 4 transports (stdio, HTTP, SSE, WebSocket). Every AI-driven optimization the pipe performs — model routing, context compaction, tool selection — fails open: no key configured behaves exactly like NeuroLink without it, and routing uses asymmetric confidence thresholds (upgrade at 0.3, downgrade at 0.6) rather than a single cutoff, because a wrong downgrade costs more than a wrong upgrade. Switch providers with a single parameter change, leverage built-in tools plus any MCP-compliant tool server, deploy with confidence using enterprise features like Redis memory and multi-provider failover, and optimize costs automatically with intelligent routing. Use it via our professional CLI or TypeScript SDK—whichever fits your workflow.
Where we're headed: We're building for the future of AI—edge-first execution and continuous streaming architectures that make AI practically free and universally available. Read our vision →
What's New
// decide() — a third inference type: calibrated judgments, not text (next)
// Enable with a decision provider's key, e.g. TYPESAFE_API_KEY (or AI_GATEWAY_API_KEY via Vercel AI Gateway).
import { NeuroLink, readDecisionChoice } from "@juspay/neurolink";
const neurolink = new NeuroLink();
const result = await neurolink.tryDecide({
// null if no decision provider is configured
state: ticketText,
questions: {
team: {
type: "choice",
instructions: "Which team should handle this?",
criteria: { billing: "Payments", technical: "Bugs", sales: "Pricing" },
},
urgent: { type: "boolean", instructions: "Is this urgent?" },
},
});
const team = result && readDecisionChoice(result.answers, "team");
if (team && team.confidence > 0.7) {
route(team.choice); // "billing" | "technical" | "sales", plus a full ranking
}
// Multi-Provider Voice (v9.62.0) — TTS + STT
// Voice is configured via the `tts` / `stt` options on generate() / stream(),
// not via dedicated synthesizeSpeech / transcribeAudio methods.
// Text in, audio out (TTS)
const result = await neurolink.generate({
input: { text: "Hello from NeuroLink" },
provider: "vertex",
tts: {
enabled: true,
voice: "en-US-Neural2-C",
format: "mp3",
output: "./output.mp3", // optional: save to disk
provider: "elevenlabs", // optional override: openai-tts | elevenlabs | google-ai | vertex | azure-tts | fish-audio | cartesia
},
});
// result.audio: { buffer: Buffer, format: "mp3", ... }
// Audio in (STT), text out
const transcript = await neurolink.generate({
input: { text: "Transcribe and summarize" },
provider: "openai",
stt: {
enabled: true,
audio: audioBuffer, // Buffer of the audio file
provider: "whisper", // whisper | deepgram | google-stt | azure-stt
language: "en-US",
},
});
// Real-time bidirectional voice (OpenAI Realtime / Gemini Live)
import { RealtimeProcessor } from "@juspay/neurolink";
await RealtimeProcessor.connect(
"openai-realtime",
{ provider: "openai-realtime", model: "gpt-4o-realtime-preview" },
{ onAudio, onTranscript, onError, onFunctionCall },
);
// AutoResearch — autonomous experiment loop (v9.53.0)
import { resolveConfig, ResearchWorker } from "@juspay/neurolink/autoresearch";
const config = resolveConfig({
repoPath: "/path/to/repo",
mutablePaths: ["train.py"],
runCommand: "python3 train.py",
metric: {
name: "val_bpb",
direction: "lower",
pattern: "^val_bpb:\\s+([\\d.]+)",
},
});
const worker = new ResearchWorker(config);
await worker.initialize("experiment-1");
const result = await worker.runExperimentCycle("Try lower learning rate");
// Provider Fallback Policy (v9.58.0) — fires only on ModelAccessDeniedError
import { NeuroLink, ModelAccessDeniedError } from "@juspay/neurolink";
const neurolink = new NeuroLink({
// Async callback. Single error arg. Return null to give up,
// or { provider?, model? } to retry with a substitute.
providerFallback: async (error) => {
if (
error instanceof ModelAccessDeniedError &&
error.allowedModels?.length
) {
return { model: error.allowedModels[0] };
}
return null;
},
// Sugar over providerFallback: if no callback is set, NeuroLink walks this list
// on each access denial. modelChain is `string[]` only (model names; same provider).
modelChain: ["claude-opus-4-7", "claude-sonnet-4-6", "gpt-4o"],
});
- Sharp image compression (v9.50.0) – Automatic image compression for AI providers via the sharp library; reduces upload bandwidth and bypasses provider size limits.
- Redis URL/TLS (v9.49.0) – Redis URL-based connections with TLS support for secure conversation memory in production.
- TaskManager (v9.41.0) – Scheduled and self-running AI tasks; cron-style execution with state checkpointing.
- Multi-user memory retrieval (v9.40.0) – Per-user memory storage and retrieval with customizable prompts.
- Evaluation Scoring (14 scorers) (v9.37.0) – Modular evaluation system with 14 scorers, pipelines, and CLI for offline quality assessment.
- Browser-compatible bundle (v9.34.0) – Client-side SDK bundle for browser use; no Node.js dependency for the core API.
- Per-call memory control (v9.33.0) – Read/write memory control per
generate()andstream()call. - Server Adapters (v8.43.0) – HTTP server with Hono, Express, Fastify, Koa. Foreground/background modes, route management, OpenAPI generation. → Guide
- External TracerProvider (v8.43.0) – Integrate NeuroLink with existing OpenTelemetry setups. → Guide
- Title Generation Events (v8.38.0) –
conversation:titleGeneratedevent +NEUROLINK_TITLE_PROMPTcustom titles. → Guide - Video Generation with Veo (v8.32.0) – Video generation via Google Veo 3.1 on Vertex AI. 720p/1080p, portrait/landscape. → Guide
- Image Generation (v8.31.0) – Native image generation with Gemini and Imagen models. → Guide
- HTTP/Streamable HTTP Transport (v8.29.0) – Remote MCP servers via HTTP with auth headers, retry, rate limiting. → Guide
- PPT Generation – 35 slide types, 5 themes, optional AI-generated images. Works across supported AI providers. → Guide
- Structured Output with Zod – Type-safe JSON via
schema+output.format: "json". → Guide - CSV & PDF File Support – Attach CSV/PDF with auto-detection. PDF: native visual analysis on Vertex, Anthropic, Bedrock, AI Studio. → CSV | PDF
- LiteLLM, SageMaker & OpenRouter – 100+ models via LiteLLM, custom endpoints on SageMaker, 300+ via OpenRouter. → LiteLLM | SageMaker
- HITL & Guardrails – Human-in-the-loop approval workflows and content filtering. → HITL | Guardrails
- Redis Conversation Export – Export full session history as JSON for analytics and audit. → Guide
Decide: Calibrated Judgments, Not Text
NeuroLink now supports decision models — a third inference type, served by hosted providers and by open-weights models you can run yourself.
decide sits alongside generate and stream. Instead of tokens, a decision
model takes one state plus a map of named typed questions and returns one
typed, calibrated answer per question, all in a single parallel pass — no
text output anywhere, so nothing has to be parsed back out of prose.
Public API: neurolink.decide() and the fail-open neurolink.tryDecide()
(returns null instead of throwing). The CLI has a thin wrapper over decide(),
neurolink decide [state] — see the CLI reference.
A score is probability-weighted, so it can land between rubric levels —
useful for sorting a queue, not just bucketing it.
What you can build with it
The model is fast, cheap and calibrated, but ~68% accurate (see the trade-off below). That combination fits work that is batched, gated and reversible — where a wrong answer is caught by a threshold or a human, not shipped to a user.
Do not use it for a final answer a user reads, an irreversible action with no
confirmation step, or anything needing a rationale — a decision carries a
probability, never an explanation. Those belong to generate.
Enabling it
Set a decision provider's key. For TypeSafe Jev
(AIProviderName.TYPESAFE, aliases jev / typesafe-ai) that is
TYPESAFE_API_KEY, and it needs nothing else. It is also reachable through the
Vercel AI Gateway via AI_GATEWAY_API_KEY; force one transport with
TYPESAFE_TRANSPORT=direct|gateway. Per-request credentials work as they do for
every other provider.
Laya is a decision provider —
Convai Innovations' Apache-2.0, open-weights "System One" model, for
when you'd rather run the decision model on your own infrastructure than call a
hosted one. There is no built-in endpoint: set LAYA_API_KEY and
LAYA_BASE_URL to point at a Laya server you run yourself, or a LiteLLM proxy
with a pass-through route to one (or pass credentials.laya to
new NeuroLink({ credentials }), or per call). Its encoders read a much
shorter state than TypeSafe's — about 768 tokens on the default
typed-decisions checkpoint (320 on english/auto), against TypeSafe's
~33,000 — so it fits short, structured decisions rather than long context.
Every built-in consumer below asks for the first configured decision provider,
in the order TypeSafe, Laya, XOR, SubQ, Perplexity, Cloudflare Clef, OpenAI Decisions, ScaleDown: with
TypeSafe and Laya both configured, TypeSafe runs; with only Laya's key and base URL
set, Laya runs.
XOR is Juspay's Apache-2.0,
open-weights decision model (xor-latest for text, xor-omni for an image, audio and value extraction); setup is on
Hugging Face. It has no built-in endpoint
either: set XOR_API_KEY and XOR_BASE_URL to the origin of a deployment or of
a LiteLLM proxy route (or pass credentials.xor). XOR counts only with both its
key and base URL set, and a call can always name it with provider: "xor". It
accepts one image and one audio clip (WAV, FL