@juspay/neurolink 13.0.1 → 13.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -2
- package/dist/browser/neurolink.min.js +419 -419
- package/dist/client/reactHooks.d.ts +2 -5
- package/dist/core/toolRouting.js +9 -6
- package/dist/core/toolRoutingDecision.js +5 -3
- package/dist/server/openapi/schemas.js +2 -2
- package/dist/server/routes/agentRoutes.d.ts +9 -2
- package/dist/server/routes/agentRoutes.js +35 -9
- package/dist/server/routes/index.js +1 -1
- package/dist/server/utils/agentInput.d.ts +53 -0
- package/dist/server/utils/agentInput.js +304 -0
- package/dist/types/client.d.ts +38 -3
- package/dist/types/server.d.ts +45 -0
- package/docs-site/static/search-index.json +6 -5
- package/package.json +2 -1
|
@@ -3367,7 +3367,7 @@
|
|
|
3367
3367
|
{"objectID":"86d184ec9e501d4e94e973c833eaee71bb40744e683334ad36c497c3f625387f","title":"Cloudflare Clef, on Workers AI","url":"/docs/features/decide-inference-type#cloudflare-clef-on-workers-ai","content":"Cloudflare's clef and clef-flash are hosted on Workers AI at a public\nendpoint, so there is no base URL to set. The account id is part of the route, so\nClef counts as configured only with both the token and the account id. They can\nequally come from the config passed to the SDK,\nnew NeuroLink({ credentials: { cloudflareClef: { apiKey, accountId } } })\n(baseURL is optional), or per call; config set there counts when a decide()\ncall picks the default decision provider, exactly as the environment does. The\nclassifier router's auto gate counts them too, per-call credentials included,\nso a credentials.cloudflareClef passed on one call can make auto pick jev.\nThe provider id is cloudflare-clef: the cloudflare provider is the Workers AI text\nprovider, which serves generate() and stream() and not decide(), and\ncredentials.cloudflare does not configure decide.\n\nThe Workers AI endpoint's state window changed during October 2026.\nCloudflare documents a 64K window; until 2026-10-04 text past about 2,048 tokens\nwas ignored without an error, and on 2026-10-07 states of at least 190,153 tokens\n(clef-flash) and 52,154 (clef) were read in full (hosted service or model:\nunknown). NeuroLink refuses a state it estimates at more than 16,000 tokens with\nmax_tokens_exceeded, which every built-in consumer treats as \"carry on as\nbefore\"; see Limits and gotchas. Latency grows with the\nstate, about 0.2 s per 1,000 tokens on large ones, so NeuroLink's default timeout\nadds 250 ms per 1,000 estimated tokens.\n\nCLOUDFLARE_API_KEY and CLOUDFLARE_ACCOUNT_ID are shared with that text\nprovider. A host that set them only to use Workers AI text has therefore also\nconfigured decide, and built-in features will use Clef whenever none of\nTypeSafe, Laya, XOR, SubQ or Perplexity is configured. Clef comes after\nTypeSafe, Laya, XOR, SubQ and Perplexity, so it never displaces one that is. No switch turns it off while the two\nvariables are set.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Cloudflare Clef, on Workers AI","lvl3":""}},
|
|
3368
3368
|
{"objectID":"08fd87a8baa41fd742824c8457907e72804c393825cb2f67997a356c98b4211b","title":"OpenAI Decisions, at its hosted endpoint","url":"/docs/features/decide-inference-type#openai-decisions-at-its-hosted-endpoint","content":"OpenAI's Decisions API is a public beta at a public endpoint, so a key alone\nconfigures it and there is no base URL to set. NeuroLink calls\n<base URL>/v1/decisions; a trailing /v1 on an override is accepted. The key\ncan equally come from the config passed to the SDK,\nnew NeuroLink({ credentials: { openaiDecisions: { apiKey } } }), or per call;\nconfig set there counts when a decide() call picks the default decision\nprovider, exactly as the environment does. The classifier router's auto gate is\nread differently: it looks at the constructor's credentials and the environment\nonly, so a credentials.openaiDecisions passed on one call does not influence\nit. The provider id is openai-decisions: the openai provider is the chat\nprovider, which serves generate() and stream() and not decide(), and\ncredentials.openai does not configure decide. Its wire is OpenAI's own (named\nquestions in an array, an array of answers), so NeuroLink translates both ways;\nthe question types you write are unchanged. See the provider guide's\nwire mapping.\n\nOPENAI_API_KEY is shared with that chat provider. A host that set it only to\nuse OpenAI chat has therefore also configured decide, and built-in features will\nuse OpenAI Decisions whenever none of TypeSafe, Laya, XOR, SubQ, Perplexity or Cloudflare\nClef is configured. It comes last in the order, so it never displaces one that is.\nThe built-in consumers (model routing, tool routing, relevance compaction, the\nsummary gate, RAG planning) and the speech-to-text correction check then make paid\ndecision calls, though they still fail open. No switch turns it off while the key\nis set (short of a gateway OPENAI_BASE_URL, below). neurolink.decide() and tryDecide() build a fresh provider for every\ncall, so a key OpenAI rejects costs one failing request per decision site each\ntime, and the 401 latch never carries across calls. The provider guide explains\nwhen NeuroLink uses it\nand\nhow the two providers share the key.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"OpenAI Decisions, at its hosted endpoint","lvl3":""}},
|
|
3369
3369
|
{"objectID":"7990ffc08aca0afbeae4310cfdcd3758daf52da4d9edd1da90a82b683f4d7d41","title":"Two transports","url":"/docs/features/decide-inference-type#two-transports","content":"The same model is reachable two ways. Which one runs is decided once, in the\nconstructor:\n\n| | Direct | Vercel AI Gateway |\n| ------------------- | ------------------ | --------------------------------------------- |\n| Key | TYPESAFE_API_KEY | AI_GATEWAY_API_KEY |\n| Endpoint | api.typesafe.ai | ai-gateway.vercel.sh/v4/ai/evaluation-model |\n| Model named in | request body | ai-model-id header |\n| Question vocabulary | noul | boolean |\n| confidence | on each answer | on providerMetadata, not on the answer |\n| Billed by | TypeSafe | Vercel |\n\nHolding both keys keeps the direct transport, so the confidence figures a\nhost already sees do not shift underneath it when a second key appears. Both\ntransports report the vendor's calibrated confidence — the gateway simply puts\nit somewhere else, under providerMetadata.typesafe.confidence.<questionId>,\nleaving the answer objects without one. Set TYPESAFE_TRANSPORT=gateway (or\ncredentials.typesafe.transport) to override.\n\n⚠️ Read that field, not the distribution peak. It is tempting to take\nmax(probabilities) when an answer carries no confidence, and on a\nnear-certain answer the two agree. On an uncertain one they do not, and not by a\nlittle: a measured four-way choice returned probabilities\n{alpha 0.16, beta 0.28, gamma 0.33, delta 0.23} — a peak of 0.33 against a\nreported confidence of 0.10. That gap straddles the default\nminUpgradeConfidence of 0.3, so the derived number clears a bar the real one\nfails and a near-random pick gets acted on as a confident one. The peak stays as\nthe fallback when neither source reports a confidence, and it is genuinely a\ndifferent quantity: an even distribution over N options lands near 1/N, not 0.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Two transports","lvl3":""}},
|
|
3370
|
-
{"objectID":"e5df7db87d4cb31c67fcce769cf5a3573764cb358ed9ee4b41f7ce86cb3954b7","title":"Using it","url":"/docs/features/decide-inference-type#using-it","content":"readDecisionBoolean / readDecisionChoice / readDecisionScore validate at\nruntime and return undefined for a missing id or a mismatched type, so no\ncall site needs a type assertion.\n\nUse decide() instead of tryDecide() when you want the failure to surface;\nit throws a ProviderError whose cause carries a typed kind\n(authentication, rate_limit, max_tokens_exceeded, …).\n\nMore questions than a provider takes. A provider that caps the questions in\none request (Laya and Cloudflare Clef take 64) refuses a longer map from decide() with\nmax_tokens_exceeded. tryDecide(), which every built-in consumer calls,\nsplits the map at the cap instead, keeps the questions in the order given, runs\nup to four batches at a time and joins the answers into one result: usage is\nsummed, the latency is the slowest batch's, and requestId lists the batches'\nids. A batch that fails costs only its own questions, which then have no answer\n(the read* helpers return undefined for them, and every built-in consumer\ncarries on without that decision); tryDecide() returns null only when every\nbatch failed. The state and any media are sent with each batch, so a split\nrequest costs the state's tokens once for each batch. A provider with no cap\n(TypeSafe, XOR, OpenAI Decisions) always gets one request.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Using it","lvl3":""}},
|
|
3370
|
+
{"objectID":"e5df7db87d4cb31c67fcce769cf5a3573764cb358ed9ee4b41f7ce86cb3954b7","title":"Using it","url":"/docs/features/decide-inference-type#using-it","content":"readDecisionBoolean / readDecisionChoice / readDecisionScore validate at\nruntime and return undefined for a missing id or a mismatched type, so no\ncall site needs a type assertion.\n\nticketText is attacker-controlled, so the verdict is a hint: keep assignTo\nreversible or put a deterministic check in front of it (see the Untrusted input\nbullet under What it is bad at).\n\nUse decide() instead of tryDecide() when you want the failure to surface;\nit throws a ProviderError whose cause carries a typed kind\n(authentication, rate_limit, max_tokens_exceeded, …).\n\nMore questions than a provider takes. A provider that caps the questions in\none request (Laya and Cloudflare Clef take 64) refuses a longer map from decide() with\nmax_tokens_exceeded. tryDecide(), which every built-in consumer calls,\nsplits the map at the cap instead, keeps the questions in the order given, runs\nup to four batches at a time and joins the answers into one result: usage is\nsummed, the latency is the slowest batch's, and requestId lists the batches'\nids. A batch that fails costs only its own questions, which then have no answer\n(the read* helpers return undefined for them, and every built-in consumer\ncarries on without that decision); tryDecide() returns null only when every\nbatch failed. The state and any media are sent with each batch, so a split\nrequest costs the state's tokens once for each batch. A provider with no cap\n(TypeSafe, XOR, OpenAI Decisions) always gets one request.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Using it","lvl3":""}},
|
|
3371
3371
|
{"objectID":"7232a490e9e72e01dbe1a12de9470a38ed66ef91aa076b8c8cc745770eb03545","title":"From the CLI","url":"/docs/features/decide-inference-type#from-the-cli","content":"The same primitive is available as neurolink decide [state], which calls\ndecide() (not tryDecide()) and prints one line per answer:\n\nTo ask about an image or a video, add --image <path> (repeatable) or\n--video <path>. XOR reads both, Perplexity, Cloudflare Clef and OpenAI Decisions\nread images only, and TypeSafe, Laya and SubQ read neither:\n\nSee the CLI command reference for the full flag\nlist, including --state-file, --questions-file, --image, --video and\n--format json.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"From the CLI","lvl3":""}},
|
|
3372
3372
|
{"objectID":"3b801c727cb399feb7390c3ad67aba9ea5f77581096bb852b7aafb87b70998aa","title":"A choice answer is also a ranking","url":"/docs/features/decide-inference-type#a-choice-answer-is-also-a-ranking","content":"readDecisionChoice returns ranked — every option sorted by probability,\nhighest first. One choice question over N options therefore ranks all N in a\nsingle request. This is the basis for picking from a large catalogue.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"A choice answer is also a ranking","lvl3":""}},
|
|
3373
3373
|
{"objectID":"e67682840a5ce9650dba2a1d437b0dfbba456cae60fa3f607127e209bf1ec3e7","title":"Images and video","url":"/docs/features/decide-inference-type#images-and-video","content":"A decision provider whose descriptor declares media limits reads images, and\npossibly one video, alongside state. XOR does, and so do Perplexity, Cloudflare\nClef and OpenAI Decisions, which declare images only and no video; TypeSafe, Laya and SubQ\ndo not. Two optional fields on the request carry them, for decide() and\ntryDecide() alike:\nimages — up to 8 images, the limit XOR, Perplexity and OpenAI Decisions each\n declare (OpenAI's is NeuroLink's own allowance, not a limit OpenAI documents);\n Cloudflare Clef takes up to 4.\nvideo — one video, for a provider that declares video (XOR).\n\nEach image and the video takes the same three input forms:\na Buffer;\na local file path;\na data:image/…;base64, or data:video/…;base64, URL.\n\nNeuroLink identifies a Buffer or a file from its bytes, not its extension — PNG,\nJPEG, WebP and GIF images, and MP4, MOV and WebM video —\nand sends it as a data: URL. A data: URL you pass yourself must hold base64\nimage or video content. Clef normalizes image/jpg to image/jpeg; other data URLs are sent as given. Perplexity and Cloudflare Clef read\nPNG, JPEG and WebP only, and refuse a GIF before any request. OpenAI Decisions\nsends every image as an inline data URL and checks no format list, because\nOpenAI's list is not established.\n\nWhat is refused. Everything NeuroLink can check is refused before any\nrequest, as a non-retryable invalid_request:\nan http(s) URL — media is not fetched for you, so pass a Buffer, a file path\n or a data: URL;\na string that is not a file path or a data: URL, such as bare base64 or a\n URL with another scheme;\na missing file, a directory, or an empty Buffer or file;\nsomething that is not an image or a video;\nmore than 8 images, or more than 4 for Cloudflare Clef;\na request body over the provider's limit: 8 MB for XOR, 32 MiB for Perplexity\n and for OpenAI Decisions (NeuroLink's own number for the latter), 256,000 bytes\n for Cloudflare Clef.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Images and video","lvl3":""}},
|
|
@@ -3381,7 +3381,7 @@
|
|
|
3381
3381
|
{"objectID":"e399806055971566454170aeec7214ec9b5948c8e3a35731a9c64b4ee2be7c21","title":"One funnel for all five sites","url":"/docs/features/decide-inference-type#one-funnel-for-all-five-sites","content":"Every one of those calls is stamped with a site — routing, toolRouting,\ncontextRelevance, summaryGate or ragPlan (the DecisionSite union) — and\ngoes through one private path on NeuroLink, which is also where a bound\ntryDecide() lands. For the four sites that run inside a NeuroLink request —\nrouting, toolRouting, contextRelevance and summaryGate — that path\nforwards the outer generate() / stream() call's per-call credentials,\nabortSignal and requestId (the top-level option, else\ncontext.requestId) to the decision, so a request that carries\ncredentials: { laya: {...} } routes and compacts against that account\nrather than the instance's; for routing the per-call credentials also count\ntowards the auto strategy's activation, so a host that holds no decision key\nitself still routes a request that carries one. ragPlan runs inside a\nhost-wired RAGPipeline, outside any NeuroLink request, so it receives only\nwhat the host puts on the options it hands tryDecide (see \"Host-wired\nconsumers\" below). The path also adds decision.site and\ndecision.host_question_count to the model.decision span; emits\ndecision:before / decision:after on the instance emitter; and runs the\ndecisionHooks described next. Without hooks or listeners, the decision\npayload — state and questions — is unchanged; per-call credentials are still\nforwarded, so the full request on the wire (account, base URL) can differ from\nthe instance's.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"One funnel for all five sites","lvl3":""}},
|
|
3382
3382
|
{"objectID":"a472e427cc594fbcc2ea01a87a8ebf99f49ebb52d71a7d5e6ff8baa6667707d1","title":"Riding along: decisionHooks","url":"/docs/features/decide-inference-type#riding-along-decisionhooks","content":"Latency on a decision model is flat in question count, so a host with its own\nquestions about the same request pays nothing to ask them in the round trip\nNeuroLink is already making. decisionHooks on the constructor does exactly\nthat — one request per site, never a second:\n\nWhat the funnel guarantees:\n\n| Concern | Behaviour |\n| ----------------------- |","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Riding along: decisionHooks","lvl3":""}},
|
|
3383
3383
|
{"objectID":"fff45cefe577cc88ce4956ce2fbd51677da0f1d953c7c3330d96f4e26737da7e","title":"Reading the limits before you send: decisionLimits()","url":"/docs/features/decide-inference-type#reading-the-limits-before-you-send-decisionlimits","content":"neurolink.decisionLimits({ provider?, model?, credentials? }) returns the\nfigures the pre-flight check compares against, resolved for one model —\nprovider as decide() resolves it, model as model ?? the model decide() sends\n(the one registered for the provider: LAYA_MODEL / TYPESAFE_MODEL as read\nwhen providers were registered, else the default — a later change to the\nvariable moves neither), the per-model entry flattened over the base:\n\nmaxQuestions is present only for a provider that caps by question count\n(Laya); a reading without the key has no count cap, and a host should test\nfor the key rather than compare against Infinity. media is present only\nfor a provider that reads images or video (XOR, Perplexity, Cloudflare Clef,\nOpenAI Decisions); its absence is what the media refusal for TypeSafe and Laya is\nbased on.\n\nenforcedLocally says who refuses: NeuroLink itself, before any network call\n(Laya and XOR, whose servers would silently truncate or fail inside the\nengine), or the provider's server\n(TypeSafe and OpenAI Decisions, whose descriptor rows are marked advisory and are\nreported but never enforced here — a local refusal would turn a server ceiling\ninto a client one that drifts from it). estimateDecisionStateTokens is the very\nfunction the pre-flight refusal uses, so a state it sizes as fitting is sent\nand one it sizes as over is refused; pass the reading so non-ASCII text is\ncharged at the model's measured rate. A named provider is read whether or\nnot it is configured — its limits are facts about the model — while the\ndefault requires a configured provider, as tryDecide() does.\n\nLaya reads far less than Jev. About 768 tokens of state on\ntyped-decisions and multilingual, and 320 on english, auto or an\nunrecognised model name, against Jev's ~33,000. Laya's server does not refuse a\nlonger state; it answers from the first 1,024 tokens (512 on english).","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Reading the limits before you send: decisionLimits()","lvl3":""}},
|
|
3384
|
-
{"objectID":"f6543a204326fbf7f27ac5c61c2f10b76f0541f3acb61eec93291921404e1a37","title":"What it is bad at","url":"/docs/features/decide-inference-type#what-it-is-bad-at","content":"\"Cannot hallucinate\" is a claim about output shape, not answer\ncorrectness: a decision model cannot return malformed JSON or an option you\ndid not offer, but it can still be wrong. TypeSafe reports ~68% accuracy on its\nown 711-case benchmark, against ~73% for a frontier model. It wins cost and\nlatency on every row and loses accuracy on every row — so it is right for\ndecisions that are gated and reversible, and wrong for final answers.\nIt reads literally. It answers the question you wrote, not the one you\n meant. Split an ambiguous question into two and combine them in code.\nAsk about the act, not the subject. \"This task touches money\" scores high\n on ordinary code that merely concerns money. The risk question in\n classifyJev is worded to exclude writing and testing such code, precisely\n because the naive phrasing escalated everything.\nIt is not a calculator. Counting, arithmetic and date comparison are\n unreliable — dates are read as text, not ordered quantities. A score is for\n thresholding and ranking, not for reading an exact magnitude off.\nIrrelevant state costs accuracy. Filter before sending.\nIt never explains itself. No rationale field exists, which rules it out\n where a decision must be auditable.\nOption order can matter. Test with reordered criteria if a call is close.\nDon't invert criteria. A boolean whose true description means \"no\"\n performs measurably worse.\n
|
|
3384
|
+
{"objectID":"f6543a204326fbf7f27ac5c61c2f10b76f0541f3acb61eec93291921404e1a37","title":"What it is bad at","url":"/docs/features/decide-inference-type#what-it-is-bad-at","content":"\"Cannot hallucinate\" is a claim about output shape, not answer\ncorrectness: a decision model cannot return malformed JSON or an option you\ndid not offer, but it can still be wrong. TypeSafe reports ~68% accuracy on its\nown 711-case benchmark, against ~73% for a frontier model. It wins cost and\nlatency on every row and loses accuracy on every row — so it is right for\ndecisions that are gated and reversible, and wrong for final answers.\nIt reads literally. It answers the question you wrote, not the one you\n meant. Split an ambiguous question into two and combine them in code.\nAsk about the act, not the subject. \"This task touches money\" scores high\n on ordinary code that merely concerns money. The risk question in\n classifyJev is worded to exclude writing and testing such code, precisely\n because the naive phrasing escalated everything.\nIt is not a calculator. Counting, arithmetic and date comparison are\n unreliable — dates are read as text, not ordered quantities. A score is for\n thresholding and ranking, not for reading an exact magnitude off.\nIrrelevant state costs accuracy. Filter before sending.\nIt never explains itself. No rationale field exists, which rules it out\n where a decision must be auditable.\nOption order can matter. Test with reordered criteria if a call is close.\nDon't invert criteria. A boolean whose true description means \"no\"\n performs measurably worse.\nUntrusted input. Any text in state can steer a verdict: a user prompt,\n a ticket, an earlier message, a retrieved document, tool output, a\n transcript, a third-party server's description. A decision model can only\n return an option you offered, but text written to push it can still pick the\n option the author wants. The built-in consumers are advisory and fail-open,\n and none of them feeds human-in-the-loop approval or a guardrail. Their reach\n is bounded, not zero.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"What it is bad at","lvl3":""}},
|
|
3385
3385
|
{"objectID":"f51228c123e6f86e1889f9990b2592debd24cc90c1584ad7d35d1f9a7aac8b82","title":"Adding another decision provider","url":"/docs/features/decide-inference-type#adding-another-decision-provider","content":"The decide inference type is provider-neutral by construction. Another\ndecision model needs:\nAn AIProviderName member and a <Name>Models enum\n (src/lib/constants/enums.ts, outside the generated regions).\nA provider class extending SystemOneDecisionProvider\n (src/lib/providers/systemOneDecision.ts), which owns the request loop,\n retries, the auth circuit breaker and answer parsing, and supplies the\n throwing getAISDKModel() / executeStream() stubs, the same shape the\n embedding-only providers (voyage.ts, jina.ts) use. The class supplies\n its endpoint, headers, body, error parsing and messages.\nA descriptor with inferenceKinds: [\"decide\"], no auto-select ranks, and\n healthCheck: \"env-only\". That one field is what keeps a text-less model out\n of every generation fallback chain; nothing else needs to know the provider\n by name. A provider that reads images or video also declares\n decisionLimits.media; without it, a request that carries media is refused\n before any network call.\nA registration block, a credentials slice, a manifest, and the usual Tier-3\n onboarding artifacts — pnpm run verify:provider-onboarding enumerates them.\n\nThe Tier-2 catalog JSON path cannot be used: its schema pins tier: 2, accepts\nonly an 8-flag text-generation capability vocabulary, and requires\ndefaultMaxOutputTokens and pricingPerMTok.output — none of which a model\nthat emits no text can honestly supply.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Adding another decision provider","lvl3":""}},
|
|
3386
3386
|
{"objectID":"31d00aee561a454dc5082ad8002f9dbc0e33f15463cfee1636497043c8f9ee55","title":"Testing","url":"/docs/features/decide-inference-type#testing","content":"The suite drives dist/index.js only. Live tests skip without\nTYPESAFE_API_KEY; the degradation and discriminator tests run unconditionally,\nbecause \"behaves correctly with no key\" and \"a text-less provider is unreachable\nfrom generation\" are the contracts that matter most.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Testing","lvl3":""}},
|
|
3387
3387
|
{"objectID":"d0993177d0de353bf96138199dbc9fad84b1bdff72bb534dc7c6a510266e3be9","title":"Embeddings","url":"/docs/features/embeddings","content":"Embeddings\n\nStatus: Stable | Availability: SDK + CLI + Server\n\nOverview\n\nEmbeddings convert text into dense numerical vectors that capture semantic meaning. Two texts with similar meanings produce vectors that are close together in the embedding space, enabling use cases like:\nSemantic search -- find documents by meaning rather than exact keyword match\nRAG pipelines -- retrieve relevant context before generating answers\nSimilarity comparison -- measure how related two pieces of text are\nClustering and classification -- group or categorize text automatically\n\nNeuroLink exposes embeddings through two provider methods (embed() and embedMany()), two server endpoints, and indirectly through the CLI's RAG commands. Every implementation calls its provider's embeddings API directly.\n\nQuick Start\n\nProvider Support\n\nNine providers implement embedding support: OpenAI, Google AI Studio, Google Vertex, Amazon Bedrock, Cohere, Voyage, Jina, Ollama, and LiteLLM. Ollama requires a locally available embedding model; LiteLLM requires an embedding deployment on its gateway. Other providers throw a descriptive error when embed() or embedMany() is called (see Unsupported Providers below).\n\n| Provider | Default Model | Env Override | Dimensions |\n| ---------------- | ------------------------------ | --------------------------- | -------------------- |\n| OpenAI | text-embedding-3-small | OPENAI_EMBEDDING_MODEL | 1536 |\n| Google AI Studio | gemini-embedding-001 | GOOGLE_AI_EMBEDDING_MODEL | 3072 |\n| Google Vertex | text-embedding-004 | VERTEX_EMBEDDING_MODEL | 768 |\n| Amazon Bedrock | amazon.titan-embed-text-v2:0 | BEDROCK_EMBEDDING_MODEL | 1024 |\n| Cohere | embed-english-v3.0 | modelName argument | Model dependent |\n| Voyage | voyage-3.5 | VOYAGE_MODEL | Model dependent |\n| Jina | jina-embeddings-v3 | JINA_MODEL | Model dependent |\n| Ollama | nomic-embed-text | OLLAMA_EMBEDDING_MODEL | Model dependent |\n| LiteLLM | gemini-embedding-001 | LITELLM_EMBEDDING_MODEL | Deployment dependent |\n\nGoogle AI Studio and Google Vertex also accept GOOGLE_EMBEDDING_MODEL as a shared fallback environment variable.\n\nAmazon Bedrock also accepts AWS_EMBEDDING_MODEL as an alternative environment variable.\n\nSDK API\n\nprovider.embed(text, modelName?)\n\nGenerate an embedding vector for a single text string.\n\nParameters:\n\n| Name | Type | Required | Description |\n| ----------- | -------- | -------- | ------------------------------------------------------ |\n| text | string | Yes | The text to embed |\n| modelName | string | No | Override the default embedding model for this provider |\n\nReturns: Promise<number[]> -- the embedding vector.\n\nprovider.embedMany(texts, modelName?)\n\nGenerate embedding vectors for multiple texts in a single batch. Each provider implementation handles its own batching, so a model that imposes a batch-size limit is chunked to fit it. Amazon Bedrock processes each text individually via Promise.all because the Titan Embed API accepts one input at a time.\n\nParameters:\n\n| Name | Type | Required | Description |\n| ----------- | ---------- | -------- | ------------------------------------------------------ |\n| texts | string[] | Yes | The texts to embed |\n| modelName | string | No | Override the default embedding model for this provider |\n\nReturns: Promise<number[][]> -- one embedding vector per input text.\n\nResponse validation\n\nCohere, Voyage, and Jina reject responses containing empty vectors or values\nthat are not finite numbers. This changes malformed responses that previously\nreturned an empty or unusable vector into rejected promises. Valid vectors,\nincluding zero and negative values, retain their original values.\n\nEach batch must return one vector per input. Voyage and Jina additionally\nrequire complete index coverage and restore the input order when the response\narrives out of order. Cohere's float envelope and legacy flat vector envelope\nare both supported. Cohere splits inputs at 96 texts and Voyage at 128; a\nmalformed later batch rejects the entire operation instead of returning partial\nresults. Passing an empty input array to these three providers returns []\nwithout a request.\n\nValidation errors retain the providers' existing error types: ProviderError\nfor Cohere and Voyage, and Error for Jina. These checks validate the response\nboundary; they do not establish a vendor model's availability.\n\nServer API\n\nThe NeuroLink server exposes two embedding endpoints under the /api/agent route group. Both ","hierarchy":{"lvl0":"Features","lvl1":"Embeddings","lvl2":"","lvl3":""}},
|
|
@@ -4513,11 +4513,11 @@
|
|
|
4513
4513
|
{"objectID":"5594cc075cbacf6979c75d68f20b45ccff0513a1e4c7087d756491900cbb1c4d","title":"Model Detection Utilities","url":"/docs/features/thinking-configuration#model-detection-utilities","content":"NeuroLink provides utilities to check thinking support:","hierarchy":{"lvl0":"Features","lvl1":"Extended Thinking Configuration","lvl2":"Model Detection Utilities","lvl3":""}},
|
|
4514
4514
|
{"objectID":"559dd274be4e9bdfeabf680692f3830f92a5c13caefc42acfb819d9635f2dad7","title":"Important Notes","url":"/docs/features/thinking-configuration#important-notes","content":"Provider compatibility: Thinking configuration is provider-specific. Gemini uses thinkingLevel, Claude uses budgetTokens\nToken consumption: Extended thinking uses additional tokens beyond the response\nLatency impact: Higher thinking levels increase response time\nNot all models support thinking: Check supportsThinkingConfig() before enabling\nStreaming support: Thinking configuration works with both generate() and stream()","hierarchy":{"lvl0":"Features","lvl1":"Extended Thinking Configuration","lvl2":"Important Notes","lvl3":""}},
|
|
4515
4515
|
{"objectID":"4bd3d62cf46ca16e0b9a52768c51ca4bced1f07f6c32f9a141c0cbfc599bcefb","title":"See Also","url":"/docs/features/thinking-configuration#see-also","content":"API Reference\nProvider Configuration\nStreaming","hierarchy":{"lvl0":"Features","lvl1":"Extended Thinking Configuration","lvl2":"See Also","lvl3":""}},
|
|
4516
|
-
{"objectID":"ffa6f024a99609da8db45d9a02bc76178d7fac894f00af93b830f9b356e86f3c","title":"Tool / MCP routing by decision model","url":"/docs/features/tool-routing-decision-model","content":"Tool / MCP routing by decision model\n\nThe shipped tool router asks a generative model for {servers: string[]} on\na 15-second budget. That shape cannot express uncertainty — a server is in\nthe list or it is not, and the only recourse for a model that is unsure is to\ninclude it. A decision model instead\nasks one calibrated yes/no question per server, in a single round trip of\nabout 400ms and $0.00002 on TypeSafe (on Perplexity each further question adds\nabout 65 ms, up to 128 in a request; see\nits guide; on\nCloudflare Clef a request takes up to 64 questions, and tryDecide() splits a\nlarger set into batches of 64; see\nits guide; OpenAI Decisions\ndeclares no question cap, so a set goes whole and what the endpoint accepts is\nnot established, see\nits guide), and each\nanswer comes back with a real probability rather than a name that either did or\ndidn't make a list.\n\nThe degradation contract. selectServersByDecision() is used only when a\ndecision provider is configured; hosts never wire decideFn by hand — it is\nbound automatically wherever tool routing resolves, using the same\ntryDecide() that returns null on any failure or absent configuration. No\ndecision provider, a failed call, fewer than two candidate servers, or an\nanswer set that would drop nothing — any of these fall straight through to\nthe existing generative router, unchanged.\n\nOne question per server\n\nEach routable server gets its own boolean question, built from its\ndescription (or, absent one, its tool names):\n\nA server is excluded only on a confident false — minDropConfidence\ndefaults to 0.6. undefined (unanswered, malformed, or too close to a\ncoin flip) and a confident true both keep the server. This is the same\nasymmetry as the classifier's upgrade/downgrade bars: keeping an unneeded\nserver costs a few hundred tokens of tool definitions; dropping a needed one\nbreaks the turn outright, because the model can never call a tool it was\nnever shown and has no way to ask for it back.\n\nTwo size guards bound the request: at most 200 servers are asked about\nin one batch (MAX_SERVERS), and the query text sent as state is capped at\n10,000 characters. Servers past the cap are never asked about and are\ntherefore always kept — a server that was not offered to the model must\nnever be silently dropped by its own absence from the question set.\n\nNeuroLink refuses a state it estimates at more than 16,000 tokens with\nmax_tokens_exceeded. A query long enough to be estimated above that is refused,\nand routing falls through to the generative router, as it does on any failure.\n\nThe wording that made this work: a measured A/B result\n\nThe first phrasing tried was the obvious one: \"answering this request will\nrequire calling at least one tool from this server,\" with false meaning\n\"this server is unrelated, OR the request needs no tool at all.\" Measured\nagainst a 10-request × 5-server labelled set, it separated correctly but\nweakly — unrelated servers averaged p = 0.31 and reached as high as\n0.80, so at the 0.6 drop bar only 12 of 39 unneeded servers were\nactually dropped.\n\nThree changes fixed it: naming the server explicitly, asking in the present\ntense about what carrying out the request involves rather than what\n\"will require,\" and splitting the bundled false criterion (which was\nreally two separate claims joined by \"or\") into one single claim. That\nmoved unrelated servers to a mean of p = 0.03 with a maximum of 0.35\n— 37 of 39 dropped at the same 0.6 bar, still with zero wrong drops.\n\nThe lesson generalises past this one question: a decision model reads\nliterally, and an \"or\" in a criterion is two questions wearing one coat. Each\nhalf of a compound criterion pulls the answer toward the middle whenever\nonly one half is true, which is exactly the muddy, hard-to-gate signal the\nfirst version produced.\n\nWhat this is bad at\nIt reasons about servers, not individual tools. The unit of decision is\n a whole MCP server; a server with twenty tools where the request needs one\n is kept or dropped as a unit, not tool-by-tool.\nThe description quality bounds the question quality. A server with no\n declared description falls back to a comma-joined list of its own tool\n names, which carries much less signal than a well-written one-line\n description — the wording fix above only helps once the server's own text\n is legible to a literal reader.\nA close call still resolves to \"keep.\" There is no partial exclusion;\n anything from a coin flip up to just under 0.6 confidence is treated\n identically to a confident true.\nIt shares the base model's general limits — literal reading, no\n arithmetic, accuracy sensitive to a noisy or oversized state — all\n described in\n what decide is bad at.\nThe query is untrusted input sent as state, and this module does not\n sanitize it. The
|
|
4516
|
+
{"objectID":"ffa6f024a99609da8db45d9a02bc76178d7fac894f00af93b830f9b356e86f3c","title":"Tool / MCP routing by decision model","url":"/docs/features/tool-routing-decision-model","content":"Tool / MCP routing by decision model\n\nThe shipped tool router asks a generative model for {servers: string[]} on\na 15-second budget. That shape cannot express uncertainty — a server is in\nthe list or it is not, and the only recourse for a model that is unsure is to\ninclude it. A decision model instead\nasks one calibrated yes/no question per server, in a single round trip of\nabout 400ms and $0.00002 on TypeSafe (on Perplexity each further question adds\nabout 65 ms, up to 128 in a request; see\nits guide; on\nCloudflare Clef a request takes up to 64 questions, and tryDecide() splits a\nlarger set into batches of 64; see\nits guide; OpenAI Decisions\ndeclares no question cap, so a set goes whole and what the endpoint accepts is\nnot established, see\nits guide), and each\nanswer comes back with a real probability rather than a name that either did or\ndidn't make a list.\n\nThe degradation contract. selectServersByDecision() is used only when a\ndecision provider is configured; hosts never wire decideFn by hand — it is\nbound automatically wherever tool routing resolves, using the same\ntryDecide() that returns null on any failure or absent configuration. No\ndecision provider, a failed call, fewer than two candidate servers, or an\nanswer set that would drop nothing — any of these fall straight through to\nthe existing generative router, unchanged.\n\nOne question per server\n\nEach routable server gets its own boolean question, built from its\ndescription (or, absent one, its tool names):\n\nA server is excluded only on a confident false — minDropConfidence\ndefaults to 0.6. undefined (unanswered, malformed, or too close to a\ncoin flip) and a confident true both keep the server. This is the same\nasymmetry as the classifier's upgrade/downgrade bars: keeping an unneeded\nserver costs a few hundred tokens of tool definitions; dropping a needed one\nbreaks the turn outright, because the model can never call a tool it was\nnever shown and has no way to ask for it back.\n\nTwo size guards bound the request: at most 200 servers are asked about\nin one batch (MAX_SERVERS), and the query text sent as state is capped at\n10,000 characters. Servers past the cap are never asked about and are\ntherefore always kept — a server that was not offered to the model must\nnever be silently dropped by its own absence from the question set.\n\nNeuroLink refuses a state it estimates at more than 16,000 tokens with\nmax_tokens_exceeded. A query long enough to be estimated above that is refused,\nand routing falls through to the generative router, as it does on any failure.\n\nThe wording that made this work: a measured A/B result\n\nThe first phrasing tried was the obvious one: \"answering this request will\nrequire calling at least one tool from this server,\" with false meaning\n\"this server is unrelated, OR the request needs no tool at all.\" Measured\nagainst a 10-request × 5-server labelled set, it separated correctly but\nweakly — unrelated servers averaged p = 0.31 and reached as high as\n0.80, so at the 0.6 drop bar only 12 of 39 unneeded servers were\nactually dropped.\n\nThree changes fixed it: naming the server explicitly, asking in the present\ntense about what carrying out the request involves rather than what\n\"will require,\" and splitting the bundled false criterion (which was\nreally two separate claims joined by \"or\") into one single claim. That\nmoved unrelated servers to a mean of p = 0.03 with a maximum of 0.35\n— 37 of 39 dropped at the same 0.6 bar, still with zero wrong drops.\n\nThe lesson generalises past this one question: a decision model reads\nliterally, and an \"or\" in a criterion is two questions wearing one coat. Each\nhalf of a compound criterion pulls the answer toward the middle whenever\nonly one half is true, which is exactly the muddy, hard-to-gate signal the\nfirst version produced.\n\nWhat this is bad at\nIt reasons about servers, not individual tools. The unit of decision is\n a whole MCP server; a server with twenty tools where the request needs one\n is kept or dropped as a unit, not tool-by-tool.\nThe description quality bounds the question quality. A server with no\n declared description falls back to a comma-joined list of its own tool\n names, which carries much less signal than a well-written one-line\n description — the wording fix above only helps once the server's own text\n is legible to a literal reader.\nA close call still resolves to \"keep.\" There is no partial exclusion;\n anything from a coin flip up to just under 0.6 confidence is treated\n identically to a confident true.\nIt shares the base model's general limits — literal reading, no\n arithmetic, accuracy sensitive to a noisy or oversized state — all\n described in\n what decide is bad at.\nThe query is untrusted input sent as state, and this module does not\n sanitize it. The reach is deliberately bounded, not zero. Server ids are\n never read back off the wire (answers are matched by position, not by name),\n so a crafted query cannot name a tool that was not already registered, and\n the ","hierarchy":{"lvl0":"Features","lvl1":"Tool / MCP routing by decision model","lvl2":"","lvl3":""}},
|
|
4517
4517
|
{"objectID":"4b84d2a2ea7a8b34624599647a02792ace2fc30650e5bb5d3da1ea68e46fdad8","title":"Tool / MCP routing by decision model","url":"/docs/features/tool-routing-decision-model#tool-mcp-routing-by-decision-model","content":"The shipped tool router asks a generative model for {servers: string[]} on\na 15-second budget. That shape cannot express uncertainty — a server is in\nthe list or it is not, and the only recourse for a model that is unsure is to\ninclude it. A decision model instead\nasks one calibrated yes/no question per server, in a single round trip of\nabout 400ms and $0.00002 on TypeSafe (on Perplexity each further question adds\nabout 65 ms, up to 128 in a request; see\nits guide; on\nCloudflare Clef a request takes up to 64 questions, and tryDecide() splits a\nlarger set into batches of 64; see\nits guide; OpenAI Decisions\ndeclares no question cap, so a set goes whole and what the endpoint accepts is\nnot established, see\nits guide), and each\nanswer comes back with a real probability rather than a name that either did or\ndidn't make a list.\n\nThe degradation contract. selectServersByDecision() is used only when a\ndecision provider is configured; hosts never wire decideFn by hand — it is\nbound automatically wherever tool routing resolves, using the same\ntryDecide() that returns null on any failure or absent configuration. No\ndecision provider, a failed call, fewer than two candidate servers, or an\nanswer set that would drop nothing — any of these fall straight through to\nthe existing generative router, unchanged.","hierarchy":{"lvl0":"Features","lvl1":"Tool / MCP routing by decision model","lvl2":"Tool / MCP routing by decision model","lvl3":""}},
|
|
4518
4518
|
{"objectID":"0b9203bc3ddca1d61b578f4bea25de508f6a241da96f270ca4742163bd99884a","title":"One question per server","url":"/docs/features/tool-routing-decision-model#one-question-per-server","content":"Each routable server gets its own boolean question, built from its\ndescription (or, absent one, its tool names):\n\nA server is excluded only on a confident false — minDropConfidence\ndefaults to 0.6. undefined (unanswered, malformed, or too close to a\ncoin flip) and a confident true both keep the server. This is the same\nasymmetry as the classifier's upgrade/downgrade bars: keeping an unneeded\nserver costs a few hundred tokens of tool definitions; dropping a needed one\nbreaks the turn outright, because the model can never call a tool it was\nnever shown and has no way to ask for it back.\n\nTwo size guards bound the request: at most 200 servers are asked about\nin one batch (MAX_SERVERS), and the query text sent as state is capped at\n10,000 characters. Servers past the cap are never asked about and are\ntherefore always kept — a server that was not offered to the model must\nnever be silently dropped by its own absence from the question set.\n\nNeuroLink refuses a state it estimates at more than 16,000 tokens with\nmax_tokens_exceeded. A query long enough to be estimated above that is refused,\nand routing falls through to the generative router, as it does on any failure.","hierarchy":{"lvl0":"Features","lvl1":"Tool / MCP routing by decision model","lvl2":"One question per server","lvl3":""}},
|
|
4519
4519
|
{"objectID":"19352c9bf82d208bbd76e4303e3e35ac7d4f7497562a4f1ee006d8cf1fae5f6b","title":"The wording that made this work: a measured A/B result","url":"/docs/features/tool-routing-decision-model#the-wording-that-made-this-work-a-measured-ab-result","content":"The first phrasing tried was the obvious one: \"answering this request will\nrequire calling at least one tool from this server,\" with false meaning\n\"this server is unrelated, OR the request needs no tool at all.\" Measured\nagainst a 10-request × 5-server labelled set, it separated correctly but\nweakly — unrelated servers averaged p = 0.31 and reached as high as\n0.80, so at the 0.6 drop bar only 12 of 39 unneeded servers were\nactually dropped.\n\nThree changes fixed it: naming the server explicitly, asking in the present\ntense about what carrying out the request involves rather than what\n\"will require,\" and splitting the bundled false criterion (which was\nreally two separate claims joined by \"or\") into one single claim. That\nmoved unrelated servers to a mean of p = 0.03 with a maximum of 0.35\n— 37 of 39 dropped at the same 0.6 bar, still with zero wrong drops.\n\nThe lesson generalises past this one question: a decision model reads\nliterally, and an \"or\" in a criterion is two questions wearing one coat. Each\nhalf of a compound criterion pulls the answer toward the middle whenever\nonly one half is true, which is exactly the muddy, hard-to-gate signal the\nfirst version produced.","hierarchy":{"lvl0":"Features","lvl1":"Tool / MCP routing by decision model","lvl2":"The wording that made this work: a measured A/B result","lvl3":""}},
|
|
4520
|
-
{"objectID":"9c9af1c1ff58051674501cb10c371fdcf50758c935a2dfa168df9719969bb7af","title":"What this is bad at","url":"/docs/features/tool-routing-decision-model#what-this-is-bad-at","content":"It reasons about servers, not individual tools. The unit of decision is\n a whole MCP server; a server with twenty tools where the request needs one\n is kept or dropped as a unit, not tool-by-tool.\nThe description quality bounds the question quality. A server with no\n declared description falls back to a comma-joined list of its own tool\n names, which carries much less signal than a well-written one-line\n description — the wording fix above only helps once the server's own text\n is legible to a literal reader.\nA close call still resolves to \"keep.\" There is no partial exclusion;\n anything from a coin flip up to just under 0.6 confidence is treated\n identically to a confident true.\nIt shares the base model's general limits — literal reading, no\n arithmetic, accuracy sensitive to a noisy or oversized state — all\n described in\n what decide is bad at.\nThe query is untrusted input sent as state, and this module does not\n sanitize it. The
|
|
4520
|
+
{"objectID":"9c9af1c1ff58051674501cb10c371fdcf50758c935a2dfa168df9719969bb7af","title":"What this is bad at","url":"/docs/features/tool-routing-decision-model#what-this-is-bad-at","content":"It reasons about servers, not individual tools. The unit of decision is\n a whole MCP server; a server with twenty tools where the request needs one\n is kept or dropped as a unit, not tool-by-tool.\nThe description quality bounds the question quality. A server with no\n declared description falls back to a comma-joined list of its own tool\n names, which carries much less signal than a well-written one-line\n description — the wording fix above only helps once the server's own text\n is legible to a literal reader.\nA close call still resolves to \"keep.\" There is no partial exclusion;\n anything from a coin flip up to just under 0.6 confidence is treated\n identically to a confident true.\nIt shares the base model's general limits — literal reading, no\n arithmetic, accuracy sensitive to a noisy or oversized state — all\n described in\n what decide is bad at.\nThe query is untrusted input sent as state, and this module does not\n sanitize it. The reach is deliberately bounded, not zero. Server ids are\n never read back off the wire (answers are matched by position, not by name),\n so a crafted query cannot name a tool that was not already registered, and\n the result is only a denylist appended to excludeTools. It can still steer\n a verdict: a confident false (0.6 by default) withholds that server's\n tools for the turn. Do not rely on this router as a security control; see\n the Untrusted input bullet under\n what decide is bad at.","hierarchy":{"lvl0":"Features","lvl1":"Tool / MCP routing by decision model","lvl2":"What this is bad at","lvl3":""}},
|
|
4521
4521
|
{"objectID":"b55a36dccb54a184ce24fa850942a8f5455cbe7f4391a23fc94f326aebeae19e","title":"See also","url":"/docs/features/tool-routing-decision-model#see-also","content":"The decide inference type\nModel routing with a decision model\nRelevance-driven compaction","hierarchy":{"lvl0":"Features","lvl1":"Tool / MCP routing by decision model","lvl2":"See also","lvl3":""}},
|
|
4522
4522
|
{"objectID":"868aff1102e3175cc67c89cc4d5bc4a20b86b1666dcd8d010b976d4b16364ece","title":"The transcribe inference type","url":"/docs/features/transcribe","content":"The transcribe inference type\n\nNeuroLink has four inference types. transcribe is the one that starts from audio:\n\n| Type | Call | Produces |\n| ---------------- | --------------------------------------------------- | -------------------------------- |\n| generate | neurolink.generate() | text |\n| stream | neurolink.stream() | text, incrementally |\n| decide | neurolink.decide() | typed judgements |\n| transcribe | neurolink.transcribe() / transcribeStream() | text from audio, with timing |\n\nIt runs through any registered speech-to-text (STT) engine and adds the layers\nthat make an engine usable on real speech: a dictionary of names and\njargon, a correction pass guarded by the decision model and finished by an\nLLM rewrite, a second-opinion engine, a fallback engine for audio the\nfirst one cannot read, and client-side streaming for engines that only\ntake whole files.\n\nZero configuration. With no STT provider configured, transcribe() uses\nWhistle, the built-in local engine: it runs on this machine, needs no key\nand no network; its model files (about 18 MB) ship inside the package.\nWhistle reads English, German, French, Spanish, Italian, Dutch and Polish; for\nother languages, accents, noisy rooms or heavy jargon, configure a cloud or\nself-hosted engine, or add a dictionary and correction.\n\nSDK\n\naudio accepts bytes (Buffer, ArrayBuffer, Uint8Array), a path, a\nfile:// URL or an http(s):// URL. The container is inferred from the path\nor the bytes; pass format (\"wav\", \"mp3\", \"m4a\", \"ogg\", \"opus\",\n\"webm\", \"flac\", \"mp4\", \"pcm16\" …) for a buffer it cannot be read from.\n\nOptions\n\n| Option | Meaning |\n| ---------------- | --------------------------------------------------------------------------------------------------------------------------------- |\n| provider | STT provider name or alias. Default: NEUROLINK_STT_PROVIDER, then the first configured provider, then Whistle. |\n| model | Model of that provider. Default: NEUROLINK_STT_MODEL, only when the provider also came from the environment. |\n| language | Language code or locale, or \"auto\". Default: NEUROLINK_STT_LANGUAGE, else the engine detects it. |\n| prompt | Context prompt for engines that bias on one; dictionary terms are appended to it. |\n| diarization | Label speakers, on engines that diarize. |\n| wordTimestamps | Ask for word-level timings. |\n| dictionary | Names and jargon, see Dictionary. |\n| correction | The correction layer, see Correction. |\n| fallback | { provider, model?, when? }, see Fallback. |\n| streaming | Tuning for transcribeStream(), see Streaming. |\n| timeoutMs | Whole-call timeout. |\n| credentials | Per-call credentials; the stt slice (credentials.stt.whisper.apiKey, credentials.stt.deepgram.apiKey …) beats the env vars. |\n\nResult\n\nTranscribeResult is the engine's STTResult (text, confidence,\nlanguage, duration, words, segments, speakers, metadata) plus what\nthe layers did:\n\n| Field | Meaning |\n| ------------------ | -------------------------------------------------------------------------------------------------------- |\n| raw | The engine's text before any correction. |\n| text | The final text — the corrected text when correction changed it, else raw. |\n| corrected | Present only when correction changed the text. |\n| languageDetected | false when the engine reported a low language-detection score. |\n| languageScores | Candidate languages with the engine's own scores, where it reports them. |\n| decisions | One record per dictionary candidate: what was heard, the ter","hierarchy":{"lvl0":"Features","lvl1":"The transcribe inference type","lvl2":"","lvl3":""}},
|
|
4523
4523
|
{"objectID":"022bf9f0cc0df8253fa229c043dc4762f656ee2c7d69e782484cb8425973befb","title":"The transcribe inference type","url":"/docs/features/transcribe#the-transcribe-inference-type","content":"NeuroLink has four inference types. transcribe is the one that starts from audio:\n\n| Type | Call | Produces |\n| ---------------- | --------------------------------------------------- | -------------------------------- |\n| generate | neurolink.generate() | text |\n| stream | neurolink.stream() | text, incrementally |\n| decide | neurolink.decide() | typed judgements |\n| transcribe | neurolink.transcribe() / transcribeStream() | text from audio, with timing |\n\nIt runs through any registered speech-to-text (STT) engine and adds the layers\nthat make an engine usable on real speech: a dictionary of names and\njargon, a correction pass guarded by the decision model and finished by an\nLLM rewrite, a second-opinion engine, a fallback engine for audio the\nfirst one cannot read, and client-side streaming for engines that only\ntake whole files.\n\nZero configuration. With no STT provider configured, transcribe() uses\nWhistle, the built-in local engine: it runs on this machine, needs no key\nand no network; its model files (about 18 MB) ship inside the package.\nWhistle reads English, German, French, Spanish, Italian, Dutch and Polish; for\nother languages, accents, noisy rooms or heavy jargon, configure a cloud or\nself-hosted engine, or add a dictionary and correction.","hierarchy":{"lvl0":"Features","lvl1":"The transcribe inference type","lvl2":"The transcribe inference type","lvl3":""}},
|
|
@@ -8268,7 +8268,8 @@
|
|
|
8268
8268
|
{"objectID":"19b651b464a6f5ce48fd3705b461d846781afb42f1bd63f1b862d0af5a7b8ed4","title":"Route Groups","url":"/docs/guides/server-adapters/api-reference#route-groups","content":"Route group factories return RouteGroup objects. Register them with adapter.registerRouteGroup(group).","hierarchy":{"lvl0":"Guides","lvl1":"Server Adapters API Reference","lvl2":"Route Groups","lvl3":""}},
|
|
8269
8269
|
{"objectID":"69d3af0a2481958a11346eed327bc59d63ae750a56f75683e1d6661de27e4e73","title":"createAllRoutes(basePath?, options?)","url":"/docs/guides/server-adapters/api-reference#createallroutesbasepath-options","content":"Creates all standard route groups in one call.","hierarchy":{"lvl0":"Guides","lvl1":"Server Adapters API Reference","lvl2":"createAllRoutes(basePath?, options?)","lvl3":""}},
|
|
8270
8270
|
{"objectID":"8af1d4e6d75ca68b8c9248b8411634663fc0eee1d650235a1e5e06122fe6c439","title":"registerAllRoutes(adapter, basePath?, options?)","url":"/docs/guides/server-adapters/api-reference#registerallroutesadapter-basepath-options","content":"Registers all route groups with an adapter. If the adapter has listRoutes(), auto-binds it for OpenAPI spec generation.","hierarchy":{"lvl0":"Guides","lvl1":"Server Adapters API Reference","lvl2":"registerAllRoutes(adapter, basePath?, options?)","lvl3":""}},
|
|
8271
|
-
{"objectID":"2a0e62a8cfac86c4b2081bf7c659fb39367ec848852b3700075feaddd6e08979","title":"Individual Route Factories","url":"/docs/guides/server-adapters/api-reference#individual-route-factories","content":"| Factory | Prefix | Endpoints |\n| -------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| createAgentRoutes(basePath?)
|
|
8271
|
+
{"objectID":"2a0e62a8cfac86c4b2081bf7c659fb39367ec848852b3700075feaddd6e08979","title":"Individual Route Factories","url":"/docs/guides/server-adapters/api-reference#individual-route-factories","content":"| Factory | Prefix | Endpoints |\n| -------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| createAgentRoutes(basePath?, options?) | /agent | POST /agent/execute -- Execute agentPOST /agent/stream -- Stream agent response (SSE)GET /agent/providers -- List available providersPOST /agent/embed -- Generate single embeddingPOST /agent/embed-many -- Generate batch embeddings |\n| createToolRoutes(basePath?) | /tools | GET /tools -- List all toolsGET /tools/search -- Search tools by queryGET /tools/:name -- Get tool detailsPOST /tools/:name/execute -- Execute toolPOST /tools/execute -- Execute tool (body-based) |\n| createMCPRoutes(basePath?) | /mcp | GET /mcp/servers -- List MCP serversGET /mcp/servers/:name -- Get server statusGET /mcp/servers/:name/tools -- List server toolsPOST /mcp/servers/:name/tools/:toolName/execute -- Execute server tool |\n| createMemoryRoutes(basePath?) | /memory | GET /memory/sessions -- List sessionsGET /memory/sessions/:id -- Get session detailsGET /memory/sessions/:id/messages -- Get session messagesDELETE /memory/sessions/:id -- Delete sessionPOST /memory/sessions/:sessionId/clear -- Clear session history |\n| createHealthRoutes(basePath?)","hierarchy":{"lvl0":"Guides","lvl1":"Server Adapters API Reference","lvl2":"Individual Route Factories","lvl3":""}},
|
|
8272
|
+
{"objectID":"69bea07b5c4ac414ed9a20d0f483fd96a7b592072d73e2fa263997e5c1aa34eb","title":"Attachments on /agent/execute and /agent/stream","url":"/docs/guides/server-adapters/api-reference#attachments-on-agentexecute-and-agentstream","content":"input.images and input.files are strings that name content. The SDK resolves\nthem itself, which is right for a program naming its own files and wrong for a\nnetwork server, so the agent routes check each one before the SDK sees it. An\nhttps:// URL or an allowed local path is read by the route and handed to the\nSDK as bytes; a data: URI already carries its content and passes through\nunchanged; anything else is refused:\n\n| Entry | Result |\n| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| data: URI | Passed through unchanged. Its length counts against the size limits below, and over a limit it is 413.","hierarchy":{"lvl0":"Guides","lvl1":"Server Adapters API Reference","lvl2":"Attachments on /agent/execute and /agent/stream","lvl3":""}},
|
|
8272
8273
|
{"objectID":"d89461a69441807c337b069b75bd37d86c2d3e0565e57b529eadb04a07da8784","title":"Proxy Route Factories","url":"/docs/guides/server-adapters/api-reference#proxy-route-factories","content":"These are only included by createAllRoutes when a proxy flag is set, and they\ntake their own dependencies rather than just a basePath.\n\n| Factory | Included when | Endpoints |\n| --------------------------------------------------------------------------------------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| createClaudeProxyRoutes(modelRouter?, basePath?, strategy?, passthrough?, primaryAccountKey?, options?) | proxy or claudeProxy | POST /v1/messages — Anthropic Messages passthrough with account poolingGET /limits — per-account quota (?snapshot=true for stored state)GET /accounts — one row per account joining status, quota and per-account token totals and cost |\n| createOpenAIProxyRoutes(modelRouter?, basePath?, loopbackPort?, runtimeConfigProvider?) | proxy or openaiProxy | POST /v1/chat/completions — OpenAI-compatible surface; Anthropic-targeted models loop back through /v1/messages |\n| createCodexProxyRoutes(basePath?)","hierarchy":{"lvl0":"Guides","lvl1":"Server Adapters API Reference","lvl2":"Proxy Route Factories","lvl3":""}},
|
|
8273
8274
|
{"objectID":"7e72ba983f827d21de4123a24256ed23c608281e7c46bfc918a5196071715853","title":"OpenAPIGenerator","url":"/docs/guides/server-adapters/api-reference#openapigenerator","content":"Class that generates OpenAPI 3.1 specifications from route definitions.","hierarchy":{"lvl0":"Guides","lvl1":"Server Adapters API Reference","lvl2":"OpenAPIGenerator","lvl3":""}},
|
|
8274
8275
|
{"objectID":"ce33eceb23cd2d0848029ad45cb1cd7c715fd120ff081bd88e7be72fe0f5a4b2","title":"Factory Functions","url":"/docs/guides/server-adapters/api-reference#factory-functions","content":"| Function | Signature | Description |\n| --------------------------- | ---------------------------------------- | ----------------------------------- |\n| createOpenAPIGenerator | (config?) => OpenAPIGenerator | Create generator with defaults |\n| generateOpenAPISpec | (routes, config?) => OpenAPISpec | One-shot spec from routes |\n| generateOpenAPIFromConfig | (serverConfig, routes?) => OpenAPISpec | Generate from ServerAdapterConfig |","hierarchy":{"lvl0":"Guides","lvl1":"Server Adapters API Reference","lvl2":"Factory Functions","lvl3":""}},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.3",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "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/call) for routing, tool selection and context budgeting. MCP-native (4 transports), voice TTS/STT/realtime, RAG, agents, memory, compaction, 9 observability exporters. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · TypeSafe Jev and more.",
|
|
6
6
|
"author": {
|
|
@@ -181,6 +181,7 @@
|
|
|
181
181
|
"test:agent-mode": "pnpm exec tsx test/continuous-test-suite-agent-mode.ts",
|
|
182
182
|
"test:servers": "pnpm exec tsx test/continuous-test-suite-servers.ts",
|
|
183
183
|
"test:server-boundaries": "pnpm exec tsx test/continuous-test-suite-server-boundaries.ts",
|
|
184
|
+
"test:agent-input-guard": "pnpm exec tsx test/continuous-test-suite-agent-input-guard.ts",
|
|
184
185
|
"test:websocket-agent-handler": "pnpm exec tsx test/continuous-test-suite-websocket-agent-handler.ts",
|
|
185
186
|
"test:tool-reliability": "pnpm exec tsx test/continuous-test-suite-tool-reliability.ts",
|
|
186
187
|
"test:video-abort": "pnpm exec tsx test/continuous-test-suite-video-abort.ts",
|