@juspay/neurolink 13.4.0 → 13.4.1
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.
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"timeouts": { "decideMs": 10000 },
|
|
26
26
|
"decisionLimits": {
|
|
27
27
|
"maxStateTokens": 922000,
|
|
28
|
+
"maxQuestions": 200,
|
|
28
29
|
"advisory": true,
|
|
29
30
|
"media": { "maxImages": 8, "video": false, "maxRequestBytes": 33554432 }
|
|
30
31
|
},
|
|
@@ -67,7 +68,7 @@
|
|
|
67
68
|
"evidence": {
|
|
68
69
|
"rosterVerified": {
|
|
69
70
|
"date": "2026-10-07",
|
|
70
|
-
"method": "OpenAI's Decisions guide and gpt-6-luna model page saved 2026-10-07: gpt-6-luna is the only model the endpoint supports. Read from documentation; no live call"
|
|
71
|
+
"method": "OpenAI's Decisions guide and gpt-6-luna model page saved 2026-10-07: gpt-6-luna is the only model the endpoint supports. The 200-question cap was read on 2026-10-17 from the questions docstring (Ask 1–200 questions about the input) in OpenAI's Python SDK, src/openai/types/decision_create_params.py in github.com/openai/openai-python, which is generated from OpenAI's API definition; the Decisions guide itself states no figure. Read from documentation; no live call, and a request over 200 questions was not tried"
|
|
71
72
|
},
|
|
72
73
|
"liveMatrix": null,
|
|
73
74
|
"addedInPR": "https://github.com/juspay/neurolink/pull/1996"
|
|
@@ -3247,7 +3247,7 @@
|
|
|
3247
3247
|
{"objectID":"a18da32e2f63d235059c36cf45cff486c8f1dc0c4d4e55ee5f239dd89ede5d21","title":"BudgetCheckResult","url":"/docs/features/context-compaction#budgetcheckresult","content":"Returned by checkContextBudget().","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"BudgetCheckResult","lvl3":""}},
|
|
3248
3248
|
{"objectID":"1a2b7ee1dace651a8300809eec11e00b29da084cbfe5b040e4760d58ea0b5879","title":"BudgetCheckParams","url":"/docs/features/context-compaction#budgetcheckparams","content":"Parameters for checkContextBudget().\n\nSource: src/lib/context/budgetChecker.ts:18-54","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"BudgetCheckParams","lvl3":""}},
|
|
3249
3249
|
{"objectID":"4bad23fd2858cc71b5af8506276229485c7d0a9636cfddae5c5d9df400bc28b8","title":"The 5-Stage Pipeline","url":"/docs/features/context-compaction#the-5-stage-pipeline","content":"The ContextCompactor runs stages sequentially. Each stage only runs if the\nprevious stage didn't bring tokens below the target budget.\n\n| # | Stage | CompactionStage | Needs a decision model |\n| --- | ------------------------- | ----------------- | -------------------------------------- |\n| 0 | Relevance drop | relevance | yes — skipped entirely without one |\n| 1 | Tool output pruning | prune | no |\n| 2 | File read deduplication | deduplicate | no |\n| 3 | LLM summarization | summarize | no (its gate uses one) |\n| 4 | Sliding window truncation | truncate | no |\n\nresult.stagesUsed reports the ones that actually ran, in order.","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"The 5-Stage Pipeline","lvl3":""}},
|
|
3250
|
-
{"objectID":"918fce938e3acd086621a86be0faaaecccf78059d8a0ef53b2dbc4fcd87347a1","title":"Stage 0: Relevance drop","url":"/docs/features/context-compaction#stage-0-relevance-drop","content":"File: src/lib/context/contextDecision.ts\n\nEverything below Stage 0 is chronological: the pipeline's only notion of\n\"droppable\" is \"old\". Stage 0 is the one stage that asks what a message is\nfor — one boolean per message (\"is this needed to answer the current\nrequest?\") in a single batch. On TypeSafe that costs the same for 200 messages\nas for one because decision latency is flat in question count; on Perplexity each\nfurther question adds about 65 ms and a request takes at most 128 (see\nits guide); on\nCloudflare Clef a request takes at most 64 questions, which tryDecide() splits\ninto batches of 64 (see its guide);\nOpenAI Decisions
|
|
3250
|
+
{"objectID":"918fce938e3acd086621a86be0faaaecccf78059d8a0ef53b2dbc4fcd87347a1","title":"Stage 0: Relevance drop","url":"/docs/features/context-compaction#stage-0-relevance-drop","content":"File: src/lib/context/contextDecision.ts\n\nEverything below Stage 0 is chronological: the pipeline's only notion of\n\"droppable\" is \"old\". Stage 0 is the one stage that asks what a message is\nfor — one boolean per message (\"is this needed to answer the current\nrequest?\") in a single batch. On TypeSafe that costs the same for 200 messages\nas for one because decision latency is flat in question count; on Perplexity each\nfurther question adds about 65 ms and a request takes at most 128 (see\nits guide); on\nCloudflare Clef a request takes at most 64 questions, which tryDecide() splits\ninto batches of 64 (see its guide);\nOpenAI Decisions takes at most 200 questions (the figure in OpenAI's Python SDK;\ngoing over it was not tried against the live endpoint), which tryDecide()\nsplits into batches of 200, so a 300-message set goes out as two requests, with\nthe state sent on each\n(see its guide);\nScaleDown declares no question cap, and its maximum is not measured\n(see its guide).\nThe 16,000-token refusal is Cloudflare Clef's own: NeuroLink refuses a state it\nestimates at more than 16,000 tokens (about 60,000 characters of prose) there, so\na longer set of eligible messages gets a refusal and the stage is skipped, as on\nany failure. A provider that declares no state limit, ScaleDown included, is sent\nthe whole state, which this stage bounds only at 300 messages of at most 1,200\ncharacters each.\n\nIt is strictly additive. With no decision provider configured the stage\ndoes not run, stagesUsed omits relevance, and the pipeline behaves exactly\nas the four-stage one always did. It is also bounded by maxDropRatio and\nwalks oldest-first, so when the cap binds it spares the newest candidates —\nthe same recency assumption every other stage makes.","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"Stage 0: Relevance drop","lvl3":""}},
|
|
3251
3251
|
{"objectID":"c1fa9b4e362150149aa7889fbd1374625457cdc5cba6f57fb15d82ef305fc492","title":"The summary gate","url":"/docs/features/context-compaction#the-summary-gate","content":"Stage 3 used to accept any non-empty string as a summary. When a decision\nmodel is configured, the generated summary is now checked first (\"does this\npreserve every decision and open question?\") and a rejected summary leaves the\nmessages untouched so a later stage can try instead. The rejection is recorded\non the span as compaction.stage3.summaryRejected, because a gate that\nsilently discarded work would be indistinguishable from one that never ran.\n\nRejection is deliberately rare: the gate exists to catch a summary that lost a\ndecision, not to second-guess wording.","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"The summary gate","lvl3":""}},
|
|
3252
3252
|
{"objectID":"2a518830a84553879be50318dfc47b77a34bf2c61cb5bc21a443ad5a5fcba95b","title":"Stage 1: Tool Output Pruning","url":"/docs/features/context-compaction#stage-1-tool-output-pruning","content":"File: src/lib/context/stages/toolOutputPruner.ts\n\nWalks messages backwards, protecting the most recent tool outputs, and replaces older tool results with \"[Tool result cleared]\".\n\nPruneConfig:\n\n| Field | Type | Default | Description |\n| ---------------- | ---------- | ----------- | ----------------------------------------------------------- |\n| protectTokens | number | 40,000 | Token budget of recent tool outputs to protect from pruning |\n| minimumSavings | number | 20,000 | Minimum tokens that must be saved for pruning to be applied |\n| protectedTools | string[] | [\"skill\"] | Tool names that are never pruned |\n| provider | string | — | Provider name for token estimation multiplier |\n\nPruneResult:","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"Stage 1: Tool Output Pruning","lvl3":""}},
|
|
3253
3253
|
{"objectID":"7c30f222482767920767c8a3dee1c3955d4b615a31c54b58851b467e409a9e64","title":"Stage 2: File Read Deduplication","url":"/docs/features/context-compaction#stage-2-file-read-deduplication","content":"File: src/lib/context/stages/fileReadDeduplicator.ts\n\nDetects multiple reads of the same file path. Keeps only the latest read, replaces earlier reads with \"[File <path> - refer to latest read below]\".\n\nDeduplicationResult:\n\nFile read detection uses the regex pattern: /(?:read|reading|read_file|readFile|Read file|cat)\\s+['\"]?([^\\s'\"\\n]+)/i\n\nA 30% savings threshold (DEDUP_THRESHOLD = 0.3) must be met for deduplication to be applied.","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"Stage 2: File Read Deduplication","lvl3":""}},
|
|
@@ -3371,7 +3371,7 @@
|
|
|
3371
3371
|
{"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 after those six in the order, so it never displaces\none that is; only ScaleDown follows it.\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":""}},
|
|
3372
3372
|
{"objectID":"691b7e7dec264cbbdcf43939939e82963f66753635c1b5ca81b26b2be05c844b","title":"ScaleDown, at its hosted endpoint","url":"/docs/features/decide-inference-type#scaledown-at-its-hosted-endpoint","content":"ScaleDown's Classify models speak the same System One wire as TypeSafe, at a\npublic endpoint, so a key alone configures it and there is no base URL to set.\nNeuroLink calls <base URL>/v1/scaledown, drops trailing slashes from an\noverride, and sends the key in an x-api-key header and never as a Bearer token.\nThe key can equally come from the config passed to the SDK,\nnew NeuroLink({ credentials: { scaledown: { apiKey } } }), or per call. The\nprovider id is scaledown; scaledown-classify names it too.\n\nScaleDown is the last decision provider, and its key is its own. Nothing\nelse reads SCALEDOWN_API_KEY, so setting it can only be meant for ScaleDown. It\nstill comes last in the order: a host with only that key gets ScaleDown for the\nbuilt-in features, and a host that also has any earlier provider configured\n(including an OPENAI_API_KEY, PERPLEXITY_API_KEY or Cloudflare pair set only for\na text provider) gets that earlier provider and reaches ScaleDown only by naming\nit. When ScaleDown is the default, the built-in consumers make paid decision\ncalls, and still fail open.\n\nIt reads text only, and the state always goes out as a string. A string state\nis sent unchanged, any other value as its JSON text, and a string that is empty or\nonly whitespace is refused before any request, as an invalid_request. {} and\n[] are sent as that text. Images and video are refused before any request. Two\noptional keys in the entry's decide block say this to the shared engine,\nauthHeader: \"x-api-key\" and stateEncoding: \"text\"; an entry that omits them\nbehaves as before. The provider guide has the\nrequest and the\nbilling note:\na choice question is scored once per option, so input tokens grow with options\ntimes state length.\n\nMuch about the endpoint is not measured, including its context size, latency,\nrate limits and the maximum number of options, questions and levels; the guide\nlists what is not measured.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"ScaleDown, at its hosted endpoint","lvl3":""}},
|
|
3373
3373
|
{"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":""}},
|
|
3374
|
-
{"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\
|
|
3374
|
+
{"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, Perplexity 128, OpenAI Decisions 200) refuses a longer map from decide() with max_tokens_exceeded, except\nOpenAI Decisions, whose row is advisory: its cap is reported and used to split,\nbut decide() sends a longer map whole and leaves the answer to the server.\ntryDecide(), which every built-in consumer calls, splits the map at the cap\ninstead, 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, SubQ, ScaleDown) always gets one request.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Using it","lvl3":""}},
|
|
3375
3375
|
{"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, SubQ and ScaleDown 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":""}},
|
|
3376
3376
|
{"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":""}},
|
|
3377
3377
|
{"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, SubQ\nand ScaleDown do 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":""}},
|
|
@@ -3384,7 +3384,7 @@
|
|
|
3384
3384
|
{"objectID":"b35e1ab2390a7b132037c293ecaf436f9ff9498591ccdd47b58ee0a6a95e7616","title":"RAG retrieval planning","url":"/docs/features/decide-inference-type#rag-retrieval-planning","content":"RAGPipelineConfig.decide lets each RAG query get its own topK/hybrid/\ngraph/rerank plan instead of one fixed configuration for every query. An\nexplicit per-call QueryOptions field always wins over the plan, and a\ncapability the pipeline wasn't configured with can never be switched on by\nit.\n\nSee per-query RAG retrieval planning\nfor the breadth rubric and why its confidence bar is deliberately lower than\ntool routing's or compaction's.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"RAG retrieval planning","lvl3":""}},
|
|
3385
3385
|
{"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":""}},
|
|
3386
3386
|
{"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":""}},
|
|
3387
|
-
{"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
|
|
3387
|
+
{"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, Cloudflare Clef, Perplexity, OpenAI Decisions); a reading without the\nkey 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, Laya, SubQ\nand ScaleDown is based 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":""}},
|
|
3388
3388
|
{"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":""}},
|
|
3389
3389
|
{"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":""}},
|
|
3390
3390
|
{"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":""}},
|
|
@@ -4530,8 +4530,8 @@
|
|
|
4530
4530
|
{"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":""}},
|
|
4531
4531
|
{"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":""}},
|
|
4532
4532
|
{"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":""}},
|
|
4533
|
-
{"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\
|
|
4534
|
-
{"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\
|
|
4533
|
+
{"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\ntakes up to 200 questions (the figure in OpenAI's Python SDK, not tried against\nthe live endpoint), and tryDecide() splits a larger set into batches of 200;\nsee\nits guide;\nScaleDown declares no question cap, and its maximum is not measured, 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","hierarchy":{"lvl0":"Features","lvl1":"Tool / MCP routing by decision model","lvl2":"","lvl3":""}},
|
|
4534
|
+
{"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\ntakes up to 200 questions (the figure in OpenAI's Python SDK, not tried against\nthe live endpoint), and tryDecide() splits a larger set into batches of 200;\nsee\nits guide;\nScaleDown declares no question cap, and its maximum is not measured, 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":""}},
|
|
4535
4535
|
{"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":""}},
|
|
4536
4536
|
{"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":""}},
|
|
4537
4537
|
{"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":""}},
|
|
@@ -6251,7 +6251,7 @@
|
|
|
6251
6251
|
{"objectID":"9fd996aaa27fb32250d5434f0e2764d8bf348370af0e011f9e447a0fdf26e3a8","title":"[SubQ](/docs/getting-started/providers/subq)","url":"/docs/getting-started/providers#subqdocsgetting-startedproviderssubq","content":"Hosted decision provider — the same typed boolean/choice/score answers as Jev, from Subquadratic's subq-snap-preview (public preview), at https://api.subq.ai\n🧭 Serves decide only (provider id subq; the aliases subquadratic and subq-snap work too); built-in features use it when it is configured and none of TypeSafe, Laya or XOR is — it comes ahead of Perplexity and Cloudflare Clef, because its key is shared with no other provider\n🔑 SUBQ_API_KEY alone configures it (keys come from console.subq.ai, shown once); SUBQ_MODEL is optional\n🖼️ No image or video input yet: SubQ's image format is not one the decide catalog can describe, so images are refused before any request\n📏 NeuroLink reports an advisory state window (376,000 estimated tokens; SubQ's own 400 response states a maximum model length of 393,216) and enforces none; no question cap is declared\n🔌 Hosted endpoint, so no base URL is needed; SUBQ_BASE_URL (or credentials.subq.baseURL) can name another origin\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[SubQ](/docs/getting-started/providers/subq)","lvl3":""}},
|
|
6252
6252
|
{"objectID":"6ab8cdd8152a0d7c9844d54b6d4eaccc905b60e79f4b28508d78d52c3cfe9470","title":"[Perplexity Decisions](/docs/getting-started/providers/perplexity-decider)","url":"/docs/getting-started/providers#perplexity-decisionsdocsgetting-startedprovidersperplexity-decider","content":"Hosted decision provider — the same typed boolean/choice/score answers as Jev, from Perplexity's pplx-decider-v1-27b, at https://api.perplexity.ai\n🧭 Serves decide only (provider id perplexity-decider, not the Sonar text provider perplexity); built-in features use it when it is configured and no TypeSafe key, no AI_GATEWAY_API_KEY, no Laya key and base URL, no XOR key and base URL and no SUBQ_API_KEY is\n🔑 PERPLEXITY_API_KEY alone configures it, and it is the same key the Perplexity text provider reads, so a key set for Sonar also lets built-in features use it when none of TypeSafe, Laya, XOR or SubQ is configured; the guide lists what each consumer then sends\n🖼️ Takes up to 8 PNG, JPEG or WebP images with a decision; no video\n💰 $0.04 per million input tokens (image tokens included), output free, as Perplexity documents it\n📏 Refuses more than about 100,000 estimated tokens of state (NeuroLink's own window; the server's ceiling is 262,144 input tokens), or more than 128 questions in a decide() call (tryDecide() splits them), before any network call. The 128-question cap, the server's token ceiling and the latency were measured on a real account in October 2026\n🔌 Hosted endpoint, so no base URL is needed; PERPLEXITY_DECIDER_BASE_URL (or credentials.perplexityDecider.baseURL) can name another origin\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[Perplexity Decisions](/docs/getting-started/providers/perplexity-decider)","lvl3":""}},
|
|
6253
6253
|
{"objectID":"94b24c75db64d3f04ba04b2ee0f04ec13bc0509de0aea1fa1b3e5516dea73ea9","title":"[Cloudflare Clef](/docs/getting-started/providers/cloudflare-clef)","url":"/docs/getting-started/providers#cloudflare-clefdocsgetting-startedproviderscloudflare-clef","content":"Hosted decision provider on Workers AI — the same typed boolean/choice/score answers as Jev, from Cloudflare's clef (27B) and clef-flash (9B), at https://api.cloudflare.com/client/v4\n🧭 Serves decide only (provider id cloudflare-clef, not the Workers AI text provider cloudflare); built-in features use it only when it is configured and none of TypeSafe, Laya, XOR, SubQ or Perplexity is — it comes after those five\n🔑 CLOUDFLARE_API_KEY (Workers AI permission) and CLOUDFLARE_ACCOUNT_ID configure it, and they are the same two variables the Cloudflare text provider reads, so a pair set for that provider also lets built-in features use it when none of TypeSafe, Laya, XOR, SubQ or Perplexity is configured\n🖼️ Takes up to 4 PNG, JPEG or WebP images with a decision; no video\n💰 $0.24 per million input tokens for clef, $0.09 for clef-flash; no output price is listed on Cloudflare's pricing page\n📏 The state window changed in October 2026 (hosted service or model: unknown): until 2026-10-04 the endpoint ignored text past about 2,048 tokens without an error, and on 2026-10-07 it read states of at least 190,153 tokens (clef-flash) and 52,154 (clef); NeuroLink refuses more than 16,000 estimated tokens (digits count a token each, punctuation 0.75, emoji 3), more than 64 questions in a decide() call (tryDecide() splits them) and a request over 256,000 bytes, base64 image data included, before any network call. The state cut and the request ceiling were measured on a real account in October 2026, with the follow-up text cuts and API limits checked on both models; see the guide for the tested shapes and dates\n🔌 Hosted endpoint, so no base URL is needed; CLOUDFLARE_CLEF_BASE_URL (or credentials.cloudflareClef.baseURL) can name another base\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[Cloudflare Clef](/docs/getting-started/providers/cloudflare-clef)","lvl3":""}},
|
|
6254
|
-
{"objectID":"bcc625210e66063fe8068d952207922cf92704dbb5424a7a3f8192f66de3bab2","title":"[OpenAI Decisions](/docs/getting-started/providers/openai-decisions)","url":"/docs/getting-started/providers#openai-decisionsdocsgetting-startedprovidersopenai-decisions","content":"Hosted decision provider (public beta) — the same typed boolean/choice/score answers as Jev, from OpenAI's Decisions API (gpt-6-luna), at https://api.openai.com/v1/decisions\n🧭 Serves decide only (provider id openai-decisions, not the OpenAI chat provider openai); built-in features use it only when it is configured and none of TypeSafe, Laya, XOR, SubQ, Perplexity or Cloudflare Clef is — it comes seventh, ahead of only ScaleDown\n🔑 OPENAI_API_KEY alone configures it, and it is the same key the OpenAI chat provider reads, so a key set for chat also lets built-in features (and a transcription dictionary's correction check) use it, and make paid decision calls, when none of the six providers ahead of it is configured, unless OPENAI_BASE_URL, OPENAI_API_BASE or credentials.openai.baseURL names a host other than https://api.openai.com (the key is then taken to be a gateway's and is not used by default; a call that names the provider still uses it and sends it to api.openai.com); the guide lists what each consumer then sends\n🖼️ Takes up to 8 images as inline data URLs with a decision (NeuroLink's own allowance, not OpenAI's); no video\n💰 $0.10 per million input tokens, input only, per OpenAI's Decisions guide as read on 2026-10-07; regional and long-context multipliers are not modelled\n📏
|
|
6254
|
+
{"objectID":"bcc625210e66063fe8068d952207922cf92704dbb5424a7a3f8192f66de3bab2","title":"[OpenAI Decisions](/docs/getting-started/providers/openai-decisions)","url":"/docs/getting-started/providers#openai-decisionsdocsgetting-startedprovidersopenai-decisions","content":"Hosted decision provider (public beta) — the same typed boolean/choice/score answers as Jev, from OpenAI's Decisions API (gpt-6-luna), at https://api.openai.com/v1/decisions\n🧭 Serves decide only (provider id openai-decisions, not the OpenAI chat provider openai); built-in features use it only when it is configured and none of TypeSafe, Laya, XOR, SubQ, Perplexity or Cloudflare Clef is — it comes seventh, ahead of only ScaleDown\n🔑 OPENAI_API_KEY alone configures it, and it is the same key the OpenAI chat provider reads, so a key set for chat also lets built-in features (and a transcription dictionary's correction check) use it, and make paid decision calls, when none of the six providers ahead of it is configured, unless OPENAI_BASE_URL, OPENAI_API_BASE or credentials.openai.baseURL names a host other than https://api.openai.com (the key is then taken to be a gateway's and is not used by default; a call that names the provider still uses it and sends it to api.openai.com); the guide lists what each consumer then sends\n🖼️ Takes up to 8 images as inline data URLs with a decision (NeuroLink's own allowance, not OpenAI's); no video\n💰 $0.10 per million input tokens, input only, per OpenAI's Decisions guide as read on 2026-10-07; regional and long-context multipliers are not modelled\n📏 Questions per request are capped at 200, the figure in OpenAI's Python SDK, and tryDecide() splits a longer set at it; going over 200 was not tried against the live endpoint, and option limits, image formats, rate limits and latency are not established (none measured). NeuroLink reports 922,000 state tokens as an advisory figure and never refuses on it\n🔌 Hosted endpoint, so no base URL is needed; OPENAI_DECISIONS_BASE_URL (or credentials.openaiDecisions.baseURL) can name another origin\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[OpenAI Decisions](/docs/getting-started/providers/openai-decisions)","lvl3":""}},
|
|
6255
6255
|
{"objectID":"900a7065e09e85ae5c74d7f57d76f6ca01ac8e2ab21e947eab38b01314b0cb52","title":"[ScaleDown](/docs/getting-started/providers/scaledown)","url":"/docs/getting-started/providers#scaledowndocsgetting-startedprovidersscaledown","content":"Hosted decision provider — the same typed boolean/choice/score answers as Jev, from ScaleDown's Classify models (classify-1 by default), at https://api.scaledown.xyz/v1/scaledown\n🧭 Serves decide only (provider id scaledown; the alias scaledown-classify works too); built-in features use it only when it is configured and none of TypeSafe, Laya, XOR, SubQ, Perplexity, Cloudflare Clef or OpenAI Decisions is — it comes last, by choice and not because its key is shared\n🔑 SCALEDOWN_API_KEY alone configures it, and no other provider reads that variable; the key is sent in an x-api-key header, never as a Bearer token\n🖼️ Text only: images and video are refused before any request, and the state is always sent as a string (a string unchanged, anything else as its JSON text; a blank string is refused locally)\n💰 USD 0.05 per million input tokens, output not charged: a list price reported by the marketing session on 2026-10-15, not measured here. A choice question is scored once per option, so input tokens grow with options times state length\n📏 Context size, latency, rate limits and the option, question and level maximums are not measured; no state window is declared and nothing is refused on size\n🔌 Hosted endpoint, so no base URL is needed; SCALEDOWN_BASE_URL (or credentials.scaledown.baseURL) can name an origin or an origin with a path prefix\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[ScaleDown](/docs/getting-started/providers/scaledown)","lvl3":""}},
|
|
6256
6256
|
{"objectID":"c98403894a115164f29a019817b7f39c93b59623a9854b4575ad06bc5f597320","title":"🧩 Additional Catalog Providers","url":"/docs/getting-started/providers#-additional-catalog-providers","content":"Every provider below is a Tier-2 catalog entry. Provider-specific\nbehavioural quirks may apply, so check the provider's catalog file. The whole\nintegration is one JSON file under src/lib/providers/catalog/. Each page is\ngenerated from that file, which is also what the CI onboarding gate reads.","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"🧩 Additional Catalog Providers","lvl3":""}},
|
|
6257
6257
|
{"objectID":"026138da0a559269ecd9f0b2ceb72d9039096e72e064142afb7bfb74a5cb7455","title":"[API Route](/docs/getting-started/providers/api-route)","url":"/docs/getting-started/providers#api-routedocsgetting-startedprovidersapi-route","content":"Claude Sonnet 4.6\n🤖 8 models; default claude-sonnet-4-6 (1M context)\n🛠️ Native tool calling + structured output together\n💳 Free tier available\n✅ Roster verified 2026-09-17 (authenticated GET /v1/models)\n🔑 API key from api-route.com\n🔄 Aliases: apiroute\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[API Route](/docs/getting-started/providers/api-route)","lvl3":""}},
|
|
@@ -6836,7 +6836,7 @@
|
|
|
6836
6836
|
{"objectID":"4c0c98775b0c21bdaeffbd51a77736e61ca1847dfea62204eab148c02317a84d","title":"What is sent to OpenAI","url":"/docs/getting-started/providers/openai-decisions#what-is-sent-to-openai","content":"OpenAI receives the state and the questions of every decision made on your\nbehalf. The questions are NeuroLink's fixed wording, plus text from your own\nconversation where a consumer quotes it; the state is where your text goes.\nThis is what each built-in consumer sends and what turns it on, read from the\ncode:\nModel routing. One request behind the router, the model catalogue and the\n per-request context budget.\nSends: the first 8,000 characters of the prompt of the call being routed,\n plus whether tools are available, whether the request includes images, the\n estimated input tokens, the requested thinking level, whether a session is\n bound and how many prior messages the caller passed in. When the pool has\n more than one model, the questions carry the ids and descriptions of the\n models in it. The images, the session id and the conversation itself are not\n sent.\nTurned on by: classifierRouter.enabled with a pool: an opt-in. With\n the default classifier: \"auto\", a configured decision provider selects the\n decision strategy. classifier: \"heuristic\" or \"llm\" never calls a\n decision provider. A call that pins both provider and model is not\n routed.\nRelevance compaction. Stage 0 of context compaction.\nSends: the current request (first 4,000 characters) and, for each earlier\n user or assistant message that is plain text (not a tool call or result, a\n summary or a pinned skill), its role and its first 1,200 characters. That\n text travels twice, once in the state and once in the message's question. By\n default the six most recent messages are never sent\n (contextRelevance.protectRecent), and at most 300 are asked about.\nTurned on by: nothing beyond a configured decision provider. It runs\n inside context compaction, which starts when a conversation outgrows its\n context budget.\nSummary-quality gate. Guards the summarization stage of compaction.","hierarchy":{"lvl0":"Getting Started","lvl1":"OpenAI Decisions Provider Guide","lvl2":"What is sent to OpenAI","lvl3":""}},
|
|
6837
6837
|
{"objectID":"ebe4c10fa9c8ba932d0fa55fd540a3c022964f71e344c17bc1f01673aa141398","title":"One key, two providers","url":"/docs/getting-started/providers/openai-decisions#one-key-two-providers","content":"OPENAI_API_KEY is the variable the OpenAI chat provider reads to\nserve generate() and stream(). It is also the variable that configures this\nprovider, and nothing else needs to be set. This changes what a host with only\nan OpenAI key does by default. A host that set the key only to use OpenAI chat\nhas also configured decide:\nWith none of TypeSafe, Laya, XOR, SubQ, Perplexity or Cloudflare Clef configured,\n the texts listed in What is sent to OpenAI go to\n OpenAI's Decisions API, and each decision is a paid call. Context compaction\n needs no other opt-in, so a host with long conversations starts sending\n conversation text the first time one outgrows its budget. Model routing, tool\n routing and RAG planning do so only where you have turned them on. A host that\n passes a transcription dictionary also sends transcript text. No code changes:\n the key is the switch.\nIt is fail-open, and the six providers ahead of it take precedence. If you\n have configured any of them, the shared key changes nothing for the built-in\n consumers. A failure here leaves behaviour as it was, so a key the Decisions\n endpoint does not accept costs requests, not correctness.\nA rejected key is not remembered across calls. A 401 stops one provider\n instance from retrying, but neurolink.decide() and neurolink.tryDecide()\n build a fresh provider for every call, so the breaker never latches across\n them. A host whose key the endpoint rejects makes one failing request for each\n decision site that runs, every time it runs.\nWith no decision provider configured at all, nothing is sent.","hierarchy":{"lvl0":"Getting Started","lvl1":"OpenAI Decisions Provider Guide","lvl2":"One key, two providers","lvl3":""}},
|
|
6838
6838
|
{"objectID":"589d4b33834cecbfd79e7a3eeac0c17d5ba4b2b1f72e19c703f9495f7604207d","title":"A gateway's key is never used for the default","url":"/docs/getting-started/providers/openai-decisions#a-gateways-key-is-never-used-for-the-default","content":"OPENAI_API_KEY is also the key of every OpenAI-compatible gateway (LiteLLM,\nvLLM, LM Studio and the like), and a host that points the chat provider at one\nsets OPENAI_BASE_URL (or, in LangChain-style setups, OPENAI_API_BASE), or an SDK\nhost passes credentials.openai.baseURL, to it. The chat provider prefers the\ncredentials field over the variable.\nThat key belongs to the gateway, and the decision text belongs on the gateway's\nside of the wire, so NeuroLink does not take such a key to be OpenAI's: while\nOPENAI_BASE_URL, OPENAI_API_BASE or credentials.openai.baseURL names a host other than\nhttps://api.openai.com, the environment key is not used to pick OpenAI Decisions\nas the default. The built-in consumers send nothing to api.openai.com for it:\neach behaves as it did without a decision model, and the \"no decision provider\"\nerror says why the key is ignored. Only a call that names the provider reaches\nOpenAI, as described below.\n\nThe check reads each value's origin, that is scheme, host and port, compared\nwithout regard to case. A path, a trailing slash and /v1 do not matter.\n\n| OPENAI_BASE_URL / OPENAI_API_BASE / credentials.openai.baseURL | The environment key is used for the default |\n| ----------------------------------------------------------------------------------- | ------------------------------------------- |\n| unset, empty or blank | yes |\n| https://api.openai.com, https://api.openai.com/v1/, https://API.openai.com | yes |\n| https://gateway.example/v1, http://127.0.0.1:4000/v1, http://localhost:11434 | no |\n| https://eu.api.openai.com, http://api.openai.com, https://api.openai.com:8443 | no: another host, scheme or port |\n| api.openai.com (no scheme), not a url, ftp://...","hierarchy":{"lvl0":"Getting Started","lvl1":"OpenAI Decisions Provider Guide","lvl2":"A gateway's key is never used for the default","lvl3":""}},
|
|
6839
|
-
{"objectID":"4578834b017bbed1b8de1a71d677386e28437557be3814e141fa7becf3e36be2","title":"What is not established","url":"/docs/getting-started/providers/openai-decisions#what-is-not-established","content":"Each item below is not measured: nothing NeuroLink was built or tested from\nsays what the endpoint does, and no live request was made. Where NeuroLink had\nto choose, it chose to send only documented fields, to refuse nothing locally on\nOpenAI's behalf, and to drop a bad answer rather than guess.\nWhether /v1/decisions uses OpenAI's general error envelope, and the status\n and text of a refusal for an over-length input. NeuroLink reads an error's\n error.message when there is one, and classifies by HTTP status.\nThe maximum number of
|
|
6839
|
+
{"objectID":"4578834b017bbed1b8de1a71d677386e28437557be3814e141fa7becf3e36be2","title":"What is not established","url":"/docs/getting-started/providers/openai-decisions#what-is-not-established","content":"Each item below is not measured: nothing NeuroLink was built or tested from\nsays what the endpoint does, and no live request was made. Where NeuroLink had\nto choose, it chose to send only documented fields, to refuse nothing locally on\nOpenAI's behalf, and to drop a bad answer rather than guess.\nWhether /v1/decisions uses OpenAI's general error envelope, and the status\n and text of a refusal for an over-length input. NeuroLink reads an error's\n error.message when there is one, and classifies by HTTP status.\nThe maximum number of choices per question (the benchmarks NeuroLink has in\n mind need 77 and 151; OpenAI's Python SDK documents 2 to 255, which NeuroLink\n does not enforce) and of levels per score, and what a question name may\n contain. The question maximum is documented (200, see\n What is sent to OpenAI), but what the endpoint\n does with more than 200 was not tried live.\nThe endpoint's input ceiling (the model page gives 922,000 input tokens for the\n model in general), the number of images per request, the request body cap and\n the accepted image formats.\nWhether probabilities always covers every supplied option, in what order, and\n how the numbers are rounded. NeuroLink reads each distribution by key, not by\n position, and requires each asked option exactly once.\nThe endpoint's rate limits. The model page lists limits for the model, not for\n this endpoint.\nHow long a request takes, for any size. The 10-second default timeout is a\n starting point.\nWhether a regional host such as https://eu.api.openai.com serves this\n endpoint with the same request. The base URL can be changed to try one.","hierarchy":{"lvl0":"Getting Started","lvl1":"OpenAI Decisions Provider Guide","lvl2":"What is not established","lvl3":""}},
|
|
6840
6840
|
{"objectID":"155654a19ca65d0e67082bb342d58723138287406b9783055a27d57d44812646","title":"Cost","url":"/docs/getting-started/providers/openai-decisions#cost","content":"$0.10 per 1M input tokens, input only, from\nOpenAI's Decisions guide\nas read on 2026-10-07. Regional and long-context multipliers are not modelled.\nNeuroLink prices a decision from the input tokens the reply reports and counts\noutput tokens at nothing, so result.usage and the CLI's Cost: line are an\nestimate from that one rate, not a bill. A reply that reports no usage is priced\nat zero.","hierarchy":{"lvl0":"Getting Started","lvl1":"OpenAI Decisions Provider Guide","lvl2":"Cost","lvl3":""}},
|
|
6841
6841
|
{"objectID":"f61611df66cdbcf4e2fb52b5095b4ec859a6a96289fc4e4be0a383f8484f3c9f","title":"Errors","url":"/docs/getting-started/providers/openai-decisions#errors","content":"| Reply | Kind | Retried |\n| -------------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------- |\n| 401 | authentication — the provider instance stops retrying | no |\n| 429 (every one) | rate_limit | no |\n| 503 | overloaded | yes, once (after Retry-After, if sent) |\n| other 5xx (500, 502, 504) | server | yes, once |\n| any other status, including 400, 402, 403 and 404 | invalid_request, with the reply's own message | no |\n| a 200 whose answers is not an array | server | no |\n| no response within the timeout | timeout | yes, once |\n| the request fails before any reply (connection refused, DNS failure) | network | yes, once |\n| the caller's own signal aborts the request | network | no |\n| more than 8 images, a video, or an unusable image (local) | invalid_request, with no network call","hierarchy":{"lvl0":"Getting Started","lvl1":"OpenAI Decisions Provider Guide","lvl2":"Errors","lvl3":""}},
|
|
6842
6842
|
{"objectID":"7cdf00f2dd7ac7f9cfae6a1b387567d1cf0c7de8a98f5c47210a6ff8221db4d6","title":"Base URL","url":"/docs/getting-started/providers/openai-decisions#base-url","content":"OPENAI_DECISIONS_BASE_URL, or credentials.openaiDecisions.baseURL, replaces\nhttps://api.openai.com. It is an origin:\ntrailing slashes and one trailing /v1 are stripped, so\n https://api.openai.com/v1/ and https://api.openai.com are the same;\nhttp:// is accepted only for localhost, 127.0.0.1 and [::1], because the\n request carries the key and the state. Any other host needs https://; 0.0.0.0\n and the rest of 127.0.0.0/8 do not count as this machine;\na user name or password, a query string, a fragment, a scheme other than\n http or https, http:// to a host other than those three, or a value that\n is not an absolute URL is refused before any request, with a message that never\n repeats the value;\na redirect from the endpoint is refused rather than followed, so the decision is\n never replayed at an address the server chooses;\nthe request goes to <origin>/v1/decisions.","hierarchy":{"lvl0":"Getting Started","lvl1":"OpenAI Decisions Provider Guide","lvl2":"Base URL","lvl3":""}},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "13.4.
|
|
3
|
+
"version": "13.4.1",
|
|
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": {
|