@juspay/neurolink 12.44.4 β†’ 12.44.6

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.
@@ -2289,9 +2289,10 @@
2289
2289
  {"objectID":"9d37e7d66f60fa6af16eaee381757f1d39b03c29d805748d72980fc766a80afc","title":"Acceptance evidence","url":"/docs/development/proxy-incident-verification#acceptance-evidence","content":"Local verification on macOS, Node 24.14.1, September 7, 2026. All network fixtures\nuse ephemeral loopback listeners and isolated storage. No installed proxy,\nprovider account, launchd service, or production request was used.\n\n| Requirement | Evidence |\n| --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Delayed acceptance gets its own full commit deadline | Actual child-process IPC fixture; no failed transfer or worker replacement |\n| A failed commit preserves unrelated streams | Actual shipped worker runtime; affected connection closes, other stream delivers every byte, replacement serves requests; commit timeouts and IPC write failures retain distinct reasons |\n| Accepted work remains identifiable after worker death | Confirmed admission append, fixture SIGKILL, independent parent exit journal, built analyzer joins by process instance |\n| Unknown outcomes remain unknown | Missing terminal plus worker exit is reported as unconfirmedAtWorkerExit; conflicting exit evidence is excluded |\n| Storage failures cannot dispatch unrecorded upstream work | HTTP fixture returns classified 503 after admission write failure; upstream invocation count stays zero |\n| Time-window analysis does not f","hierarchy":{"lvl0":"Development","lvl1":"Proxy incident reliability verification","lvl2":"Acceptance evidence","lvl3":""}},
2290
2290
  {"objectID":"e445d51bde52184ea947c95c6b1f2105e1c1dd67b2ed01509cbfa320d3a396db","title":"Performance observations","url":"/docs/development/proxy-incident-verification#performance-observations","content":"The existing lifecycle gate wrote 100,000 events for 25,000 requests with zero\ndrops or uncertain writes. Enqueue p95 was 12 microseconds; added response-tracking\np95 was 49 microseconds. The statistics gate reconciled 50,000 requests exactly.\nThe loopback transport gate added 1.69 ms p95 against its 5 ms budget.\n\nThe first rolling gate preserved all traffic but failed the sustained latency\nbudget: 51.28 ms added p95 against 25 ms. We then ran three alternating comparisons\nagainst unchanged release 382217975c39433df058e2b2c2fb91b283230725, using the\nsame fixture, machine and background scheduling priority. No budgets were changed.\n\n| Round | Release added p95 under sustained load | Patched added p95 under sustained load |\n| ----- | -------------------------------------: | -------------------------------------: |\n| 1 | 6.042 ms | 24.840 ms |\n| 2 | 6.826 ms | 5.355 ms |\n| 3 | 9.827 ms | 4.811 ms |\n\nEvery comparison passed the existing budgets, preserved the active stream, and\nreported zero dropped requests. The fixture includes 100 concurrent handoff\nrequests and 64-way sustained traffic. These observations expose variability;\nthey do not certify a latency ceiling under arbitrary host contention.","hierarchy":{"lvl0":"Development","lvl1":"Proxy incident reliability verification","lvl2":"Performance observations","lvl3":""}},
2291
2291
  {"objectID":"5cb2fe62f38e8943b94facdd1ddd6a4a968fbbb161744152fe47c3c269d575cf","title":"Interpretation limits","url":"/docs/development/proxy-incident-verification#interpretation-limits","content":"The CLI has one signal owner. Proxy workers and supervisors own their drain and\nexit; the ordinary CLI telemetry cleanup cannot exit alongside them. Repeated\nSIGINT/SIGTERM signals reuse that shutdown. Ordinary command cleanup catches\nflush failures and uses a five-second deadline. Worker and supervisor telemetry\ncleanup also has a deadline after request draining. Supervisor SIGHUP forwards a\nreload to the ready serving worker, while a candidate loads configuration during\nstartup. Isolated subprocess fixtures in test:proxy-restart exercise reload,\nduplicate signals, failed flushes, stalled flushes and drain failures. If startup\nregisters a shutdown owner during ordinary cleanup, the original signal is\ndelegated to that owner after cleanup settles, including rejection or timeout.\nSignal-triggered ordinary cleanup preserves an existing command failure code.\nSupervisor SIGHUP handling is installed before startup awaits, ignores reloads\nuntil a serving worker is ready, and forwards them during control-plane setup.\nSupervisor shutdown ownership is also registered before startup awaits. A stop\nprevents later setup stages, waits for already-started resource creation, and\ncloses the resulting resources before exiting. Cleanup continues after an\nindividual close failure and exits unsuccessfully when a resource cannot close.\nIsolated child-process regressions signal bootstrap, pending worker startup,\npending restart-control setup, and updater startup, including duplicate signals\nand a rejected control close.\nResource cleanup runs concurrently: worker creation and drain have a 35-second\ndeadline, and control cleanup has a 5-second deadline. Telemetry then has its\n5-second budget, leaving headroom inside the launchd service's 45-second stop\ntimeout. A stalled resource is reported and causes an unsuccessful exit; a late\nresource returned while telemetry is flushing is still closed without extending\nthe exit deadline. Fixtures cover permanently pending worker/control setup and a\n","hierarchy":{"lvl0":"Development","lvl1":"Proxy incident reliability verification","lvl2":"Interpretation limits","lvl3":""}},
2292
- {"objectID":"e8a7f76ea9249969c4e7f7f8767fd2cac18478baca29ee921e7a7ca73825db69","title":"Proxy package updates and token budgets","url":"/docs/development/proxy-updates-and-token-budgets","content":"Proxy package updates and token budgets\n\nAutomatic updates prepare a separate package before asking the supervisor to\nactivate it. They do not run a global package replacement over files used by\nserving workers. These changes take effect after the release is installed and\nits supervisor is activated; merging a PR does not change a running service.\n\nUpdate and restart behavior\n\nThe updater installs the current running version, when needed for rollback, and\nthe candidate under ~/.neurolink/proxy-packages/<version>. Installation uses a\nprivate temporary directory and publishes the version directory only after the\npackage name, version, executable location, and JavaScript syntax validate.\nA candidate with missing dependencies can still fail startup: actual worker\nreadiness remains the activation gate, and the serving generation is retained\nwhen replacement fails.\n\nThe package-manager process runs asynchronously. Output progress renews a\ntwo-minute inactivity deadline; a fifteen-minute maximum still bounds an\ninstaller that emits output forever. A timed-out installer and its process group\nare stopped, its unpublished directory is removed, and transient errors receive\nthe updater's bounded retry schedule. Progress telemetry contains byte counts and\ntiming, not raw package-manager output that may contain authenticated URLs.\n\nThe stable launcher selects one validated package. Its --version check reads\npackage metadata in a minimal Node process; it does not initialize provider,\ntelemetry, or proxy code. Each worker is spawned from its expected package, so a\nnew candidate cannot silently change the recovery executable of an older worker.\nRollback restores the previous selection rather than reinstalling over live\nfiles. Proxy auto-update does not change the global CLI package; invoking an older\nglobal CLI to reinstall the service retains the selected proxy package instead\nof downgrading it or rejecting its version. Version directories are intentionally retained: they can still be needed\nby active/draining generations or rollback. This increases package disk usage;\nthere is currently no automatic garbage collection of retained versions.\n\nBefore refreshing a supervisor, all of the following must be settled:\nActive requests in the current worker.\nEvery draining worker generation.\nQueued sockets and pending socket transfers.\nAny candidate worker.\n\nIncomplete rolling status is not evidence of idleness. A drain attempt lasts at\nmost thirty seconds before deferral and admission recovery; it never kills an\nolder stream to make the update proceed. The worker also has a ninety-second\nadmission recovery lease if the updater disappears. Package installation and\nvalidation finish before a legacy service closes admission.\n\nUse neurolink proxy restart --check for a read-only restart preflight and\nneurolink proxy restart for a supervisor-owned rolling replacement. A failed\ncheck does not fall back to a forced process restart. The result distinguishes a\nverified replacement from an activated worker whose final verification failed.\nA worker restart does not, by itself, upgrade the supervisor.\n\nStatus separates diskPackageVersion (metadata at the executable used by the\nreporting process), selectedPackageVersion (next launcher selection),\nvalidatedVersion (last updater-validated package), candidateVersion, the\nserving worker version, and the supervisor version. A changed disk manifest or a\nvalidated package does not prove live adoption.\n\nReinstall first refuses any running worker, draining generation, or loaded launchd\njob before writing files or changing processes. Unknown/permission-denied process\nor launchd state also refuses. Use the rolling restart command for a live service;\nexplicitly stop and unload it before an intended reinstall.\n\nFor a stopped service, reinstall reads the saved definition before writing it. Existing\nhost/port, environment-file path, routing-config path, and operator OTel/proxy\nvariables become defaults; explicit arguments and current environment values\nwin. An unreadable service definition aborts reinstall instead of silently\nremoving its settings. Worker IPC identity is not persisted. This includes\nNEUROLINK_PROXY_OTLP_BODIES_ENDPOINT, NEUROLINK_PROXY_CONTEXT_POLICY, and\nNEUROLINK_PROXY_TOKEN_BUDGET.\n\nOptional token reservations\n\nNEUROLINK_PROXY_TOKEN_BUDGET accepts a JSON object. No token cap is enabled by\ndefault. For example, an operator could configure:\n\nThese numbers are illustrative, not recommended account allowances. Supported\nfields must be positive safe integers; an invalid configuration fails closed.\nmaxInFlightTokens is per provider/account. accountWindowTokens caps charged\ntokens in that account's fixed window. sessionWindowTokens applies across\naccounts and providers for the same client session. The default window is one\nhour when a cap is set without windowMs.\n\nBefore each native upstream attempt or translated SDK invocation, the proxy\nreserves estimated input plus the output allowance. An SDK ","hierarchy":{"lvl0":"Development","lvl1":"Proxy package updates and token budgets","lvl2":"","lvl3":""}},
2292
+ {"objectID":"e8a7f76ea9249969c4e7f7f8767fd2cac18478baca29ee921e7a7ca73825db69","title":"Proxy package updates and token budgets","url":"/docs/development/proxy-updates-and-token-budgets","content":"Proxy package updates and token budgets\n\nAutomatic updates prepare a separate package before asking the supervisor to\nactivate it. They do not run a global package replacement over files used by\nserving workers. These changes take effect after the release is installed and\nits supervisor is activated; merging a PR does not change a running service.\n\nUpdate and restart behavior\n\nThe updater installs the current running version, when needed for rollback, and\nthe candidate under ~/.neurolink/proxy-packages/<version>. Installation uses a\nprivate temporary directory and publishes the version directory only after the\npackage name, version, executable location, and JavaScript syntax validate.\nA candidate with missing dependencies can still fail startup: actual worker\nreadiness remains the activation gate, and the serving generation is retained\nwhen replacement fails.\n\nThe package-manager process runs asynchronously. Output progress renews a\ntwo-minute inactivity deadline; a fifteen-minute maximum still bounds an\ninstaller that emits output forever. A timed-out installer and its process group\nare stopped, its unpublished directory is removed, and transient errors receive\nthe updater's bounded retry schedule. Progress telemetry contains byte counts and\ntiming, not raw package-manager output that may contain authenticated URLs.\n\nThe stable launcher selects one validated package. Its --version check reads\npackage metadata in a minimal Node process; it does not initialize provider,\ntelemetry, or proxy code. Each worker is spawned from its expected package, so a\nnew candidate cannot silently change the recovery executable of an older worker.\nRollback restores the previous selection rather than reinstalling over live\nfiles. Proxy auto-update does not change the global CLI package; invoking an older\nglobal CLI to reinstall the service retains the selected proxy package instead\nof downgrading it or rejecting its version. Version directories are intentionally retained: they can still be needed\nby active/draining generations or rollback. This increases package disk usage;\nthere is currently no automatic garbage collection of retained versions.\n\nBefore refreshing a supervisor, all of the following must be settled:\nActive requests in the current worker.\nEvery draining worker generation.\nQueued sockets and pending socket transfers.\nAny candidate worker.\n\nIncomplete rolling status is not evidence of idleness. A drain attempt lasts at\nmost thirty seconds before deferral and admission recovery; it never kills an\nolder stream to make the update proceed. The worker also has a ninety-second\nadmission recovery lease if the updater disappears. Package installation and\nvalidation finish before a legacy service closes admission.\n\nUse neurolink proxy restart --check for a read-only restart preflight and\nneurolink proxy restart for a supervisor-owned rolling replacement. A failed\ncheck does not fall back to a forced process restart. The result distinguishes a\nverified replacement from an activated worker whose final verification failed.\nA worker restart does not, by itself, upgrade the supervisor.\n\nStatus separates diskPackageVersion (metadata at the executable used by the\nreporting process), selectedPackageVersion (next launcher selection),\nvalidatedVersion (last updater-validated package), candidateVersion, the\nserving worker version, and the supervisor version. A changed disk manifest or a\nvalidated package does not prove live adoption.\n\nReinstall first refuses any running worker, draining generation, or loaded launchd\njob before writing files or changing processes. Unknown/permission-denied process\nor launchd state also refuses. Use the rolling restart command for a live service;\nexplicitly stop and unload it before an intended reinstall.\n\nFor a stopped service, reinstall reads the saved definition before writing it. Existing\nhost/port, environment-file path, routing-config path, and operator OTel/proxy\nvariables become defaults; explicit arguments and current environment values\nwin. An unreadable service definition aborts reinstall instead of silently\nremoving its settings. Worker IPC identity is not persisted. This includes\nNEUROLINK_PROXY_OTLP_BODIES_ENDPOINT, NEUROLINK_PROXY_CONTEXT_POLICY, and\nNEUROLINK_PROXY_TOKEN_BUDGET.\n\nLocal compatibility polyfills\n\nAn automatic package upgrade leaves the routing config, environment file, and\nlaunchd definition intact. It also preserves the exact previous package path,\nincluding when a local build and an official build share a version number.\nManaged service starts and worker replacements do not reapply CLI client\nconfiguration. User changes to Codex, Claude Code, and other client settings\nremain in place. Use explicit proxy setup or foreground proxy start to\nconfigure client routing.\n\nEach freshly staged package records its original proxy runtime files. When a\nlater upgrade is available, the updater compares the serving package with that\nbaseline and applies only the remaining local diff hunk","hierarchy":{"lvl0":"Development","lvl1":"Proxy package updates and token budgets","lvl2":"","lvl3":""}},
2293
2293
  {"objectID":"d8b758e463be06d23598c7f1722e82d46f3d5f2df3c3c98058f400923f83ac8f","title":"Proxy package updates and token budgets","url":"/docs/development/proxy-updates-and-token-budgets#proxy-package-updates-and-token-budgets","content":"Automatic updates prepare a separate package before asking the supervisor to\nactivate it. They do not run a global package replacement over files used by\nserving workers. These changes take effect after the release is installed and\nits supervisor is activated; merging a PR does not change a running service.","hierarchy":{"lvl0":"Development","lvl1":"Proxy package updates and token budgets","lvl2":"Proxy package updates and token budgets","lvl3":""}},
2294
2294
  {"objectID":"b31737c456bf0dd066337629bccccd40c4572b96ad3b51fdf48de2c44d45e82a","title":"Update and restart behavior","url":"/docs/development/proxy-updates-and-token-budgets#update-and-restart-behavior","content":"The updater installs the current running version, when needed for rollback, and\nthe candidate under ~/.neurolink/proxy-packages/<version>. Installation uses a\nprivate temporary directory and publishes the version directory only after the\npackage name, version, executable location, and JavaScript syntax validate.\nA candidate with missing dependencies can still fail startup: actual worker\nreadiness remains the activation gate, and the serving generation is retained\nwhen replacement fails.\n\nThe package-manager process runs asynchronously. Output progress renews a\ntwo-minute inactivity deadline; a fifteen-minute maximum still bounds an\ninstaller that emits output forever. A timed-out installer and its process group\nare stopped, its unpublished directory is removed, and transient errors receive\nthe updater's bounded retry schedule. Progress telemetry contains byte counts and\ntiming, not raw package-manager output that may contain authenticated URLs.\n\nThe stable launcher selects one validated package. Its --version check reads\npackage metadata in a minimal Node process; it does not initialize provider,\ntelemetry, or proxy code. Each worker is spawned from its expected package, so a\nnew candidate cannot silently change the recovery executable of an older worker.\nRollback restores the previous selection rather than reinstalling over live\nfiles. Proxy auto-update does not change the global CLI package; invoking an older\nglobal CLI to reinstall the service retains the selected proxy package instead\nof downgrading it or rejecting its version. Version directories are intentionally retained: they can still be needed\nby active/draining generations or rollback. This increases package disk usage;\nthere is currently no automatic garbage collection of retained versions.\n\nBefore refreshing a supervisor, all of the following must be settled:\nActive requests in the current worker.\nEvery draining worker generation.\nQueued sockets and pending socket transfers.\nAny candidate worker.\n\nIncom","hierarchy":{"lvl0":"Development","lvl1":"Proxy package updates and token budgets","lvl2":"Update and restart behavior","lvl3":""}},
2295
+ {"objectID":"69e1f9556ad4141f30fa78e44edc0297f70c1dcc1e775c5955e44c912f79a0b6","title":"Local compatibility polyfills","url":"/docs/development/proxy-updates-and-token-budgets#local-compatibility-polyfills","content":"An automatic package upgrade leaves the routing config, environment file, and\nlaunchd definition intact. It also preserves the exact previous package path,\nincluding when a local build and an official build share a version number.\nManaged service starts and worker replacements do not reapply CLI client\nconfiguration. User changes to Codex, Claude Code, and other client settings\nremain in place. Use explicit proxy setup or foreground proxy start to\nconfigure client routing.\n\nEach freshly staged package records its original proxy runtime files. When a\nlater upgrade is available, the updater compares the serving package with that\nbaseline and applies only the remaining local diff hunks to a new candidate.\nIndependent release changes remain intact. A fix already present in the release\nis skipped and disappears from the local diff on subsequent upgrades. The\nserving package is never edited during this reconciliation.\n\nAn overlapping change, ambiguous patch context, unsupported dependency change,\nor invalid JavaScript aborts candidate preparation. The current worker,\nlauncher, config, and rollback selection remain in place. Automatic staging\nlogs the number of files applied or already included without logging their\ncontents. Runtime JavaScript and JSON are supported; dependency trees and\nbrowser bundles are not local proxy polyfills.\n\nClean legacy installations bootstrap their baseline by comparing with a\nseparately staged registry package of the same version. An edited legacy build\ncannot be safely compared without its actual original base, so its upgrade is\nretained until that base is recorded explicitly:\n\nThis command records the original files; it does not apply edits, select a\npackage, or restart a service. Supply the pristine package from which the local\nedit was made. A different existing baseline is refused rather than overwritten.","hierarchy":{"lvl0":"Development","lvl1":"Proxy package updates and token budgets","lvl2":"Local compatibility polyfills","lvl3":""}},
2295
2296
  {"objectID":"82a142fcb5a4a408bcc1ef4a742c15da227f7efe0ca8039f32786bd317776acc","title":"Optional token reservations","url":"/docs/development/proxy-updates-and-token-budgets#optional-token-reservations","content":"NEUROLINK_PROXY_TOKEN_BUDGET accepts a JSON object. No token cap is enabled by\ndefault. For example, an operator could configure:\n\nThese numbers are illustrative, not recommended account allowances. Supported\nfields must be positive safe integers; an invalid configuration fails closed.\nmaxInFlightTokens is per provider/account. accountWindowTokens caps charged\ntokens in that account's fixed window. sessionWindowTokens applies across\naccounts and providers for the same client session. The default window is one\nhour when a cap is set without windowMs.\n\nBefore each native upstream attempt or translated SDK invocation, the proxy\nreserves estimated input plus the output allowance. An SDK invocation can contain\nprovider-internal retries that the proxy cannot observe individually; its single\nreservation does not prove or cap the combined tokens of those hidden retries. Tool definitions and instructions contribute to the input\nestimate. This is an estimate with recorded provenance, not an exact provider\ntokenization or a guarantee of monetary cost. A configured estimated input maximum\nis not a hard maximum on actual provider input tokens, especially for images,\naudio, and files. Model/context policy is configured\nseparately with NEUROLINK_PROXY_CONTEXT_POLICY; it must use the actual serving\nmodel. Provider-reported total input plus output replaces the estimate once when\ncomplete usage is known. Reasoning is already part of output and is not added a\nsecond time. Missing or uncertain usage retains the estimate. Cancellation\nbefore dispatch refunds the unused reservation; cancellation after dispatch does\nnot presume that the provider billed zero.\n\nActive and draining workers reserve atomically against one in-memory supervisor\ncoordinator. Outstanding reservations remain charged across a window boundary;\na reset cannot create new capacity for requests that are still running. Worker\nexit retains estimated spending for its unresolved calls while releasing its\nin-flight occupancy.","hierarchy":{"lvl0":"Development","lvl1":"Proxy package updates and token budgets","lvl2":"Optional token reservations","lvl3":""}},
2296
2297
  {"objectID":"183568ccdb77340136a3026e2df12e9e82c5722ba3ddbf3b5749ba6c62de231b","title":"OTLP acknowledgement boundaries","url":"/docs/development/proxy-updates-and-token-budgets#otlp-acknowledgement-boundaries","content":"Both metadata and body queues serialize through OpenTelemetry's official JSON\nserializer. A response-aware HTTP sender validates the complete, bounded response\nbefore reporting transport acknowledgement. HTTP 200 with {} or a zero-rejection\npartialSuccess warning is acknowledged. A known partial rejection leaves the\nwhole batch unconfirmed because the response does not identify the rejected\nrecords; that batch is not replayed. Empty, malformed, interrupted, oversized,\nunexpected-shape or ambiguous-alias success responses are also unconfirmed and\nare not retried. Empty JSON is not {}; the zero-byte protobuf convention does\nnot apply to this JSON sender. Canonical and proto snake_case response names are\naccepted, but duplicate aliases are conservatively rejected.\n\nTransient HTTP 429/502/503/504 and transport failures before a response may retry\nwithin the existing 30-second total export deadline, with at most five attempts\nand exponential backoff with jitter even when Retry-After is zero. Retries retain the same\nserialized event IDs and bytes, enabling query-side deduplication. Retry-After\ncannot extend the deadline. Response reads are capped at 64 KiB. The exporter\npreserves merged generic/log-specific OTLP headers, gzip request compression,\nand configured CA/client certificate/key files; invalid configuration fails\nexplicitly. It requests uncompressed JSON responses and treats unsupported\nresponse encodings as unconfirmed. Diagnostics omit collector response bodies\nand credentials. Transport acknowledgement remains distinct from backend\npersistence; query reconciliation is still needed to confirm ingestion.\n\nA staged update may finish after its original supervisor/updater has been\nreplaced. Before publishing, validation rollback, or activation, the updater\nrechecks that its recorded supervisor and updater PIDs still own the service\nand that the original parent is running. Unknown ownership defers mutation.\nStale update jobs cannot overwrite or roll back a replacemen","hierarchy":{"lvl0":"Development","lvl1":"Proxy package updates and token budgets","lvl2":"OTLP acknowledgement boundaries","lvl3":""}},
2297
2298
  {"objectID":"3d5db69fb501ec2b11df1700773d0e7648ef30c85f643c3b54975e4f45a3a05b","title":"πŸ§ͺ COMPREHENSIVE TESTING & VERIFICATION PLAN","url":"/docs/development/testing-plan","content":"πŸ§ͺ COMPREHENSIVE TESTING & VERIFICATION PLAN\nTest Results Documentation:\nUpdated Documentation:\n\nLighthouse Integration Testing Strategy\nDate: 2025-07-06 02:55 AM\nEstimated Duration: 3 hours total\n\nπŸ“‹ TESTING OVERVIEW\n\nWhat We're Testing:\nβœ… Real-time WebSocket Infrastructure - New streaming services, WebSocket server, enhanced chat\nβœ… Advanced Telemetry Integration - OpenTelemetry stack (15+ dependencies, optional by default)\nβœ… Voice AI Removal - Complete cleanup of voice dependencies and code\nβœ… Backward Compatibility - All existing functionality preserved\nβœ… New API Surface - Factory methods, exports, TypeScript interfaces\n\nCritical Success Criteria:\nβœ… Zero Breaking Changes: All existing code works unchanged\nβœ… Build Success: TypeScript compilation with 0 errors\nβœ… Performance: \\<5% overhead when new features disabled\nβœ… Optional Features: Telemetry disabled by default, WebSocket services optional\nβœ… Complete Integration: New features work with existing AI providers and MCP tools\n\nπŸ”„ PHASE A: IMMEDIATE VERIFICATION (30 minutes)\n\nPriority: CRITICAL | Blocking: Must pass before proceeding\n\nA.1 File System Verification (10 minutes)\n\nSuccess Criteria:\nβœ… WebSocket infrastructure files exist\nβœ… Streaming services files exist\nβœ… Telemetry files exist\nβœ… NO voice-related files remain\nβœ… Enhanced chat files exist\n\nA.2 Build Validation (15 minutes)\n\nSuccess Criteria:\nβœ… TypeScript compilation: 0 errors\nβœ… Vite build: successful\nβœ… CLI build: successful\nβœ… publint: \"All good!\"\nβœ… Package integrity: pnpm pack succeeds\n\nA.3 Dependency Verification (5 minutes)\n\nSuccess Criteria:\nβœ… Voice AI dependencies: 0 found\nβœ… OpenTelemetry dependencies: 15+ installed\nβœ… No dependency conflicts\nβœ… Package.json reflects changes\n\nπŸ”§ PHASE B: CORE TESTING (1 hour)\n\nPriority: HIGH | Focus: New feature functionality\n\nB.1 WebSocket Infrastructure Testing (20 minutes)\n\nTests to Create:\ntest/websocket-server.test.ts\ntest/streaming-manager.test.ts\ntest/websocket-chat-handler.test.ts\n\nSuccess Criteria:\nβœ… WebSocket server starts on specified port\nβœ… Connection management works\nβœ… Room creation/joining functional\nβœ… Streaming channels operational\nβœ… Error handling graceful\n\nB.2 Telemetry Integration Testing (20 minutes)\n\nTests to Create:\ntest/telemetryService.test.ts\ntest/ai-instrumentation.test.ts\ntest/mcp-instrumentation.test.ts\n\nSuccess Criteria:\nβœ… Telemetry disabled by default\nβœ… Telemetry enables when configured\nβœ… AI operation tracking works\nβœ… MCP tool instrumentation functional\nβœ… Zero overhead when disabled\n\nB.3 Enhanced Chat Testing (20 minutes)\n\nTests to Create:\ntest/enhanced-chat.test.ts\ntest/chat-integration.test.ts\n\nSuccess Criteria:\nβœ… Enhanced chat service creates successfully\nβœ… SSE mode works\nβœ… WebSocket mode works\nβœ… Dual mode integration functional\nβœ… Backward compatibility with existing chat\n\nπŸš€ PHASE C: COMPREHENSIVE VALIDATION (1 hour)\n\nPriority: HIGH | Focus: Integration and performance\n\nC.1 Existing Functionality Regression Testing (20 minutes)\n\nSuccess Criteria:\nβœ… All existing tests pass\nβœ… CLI commands work unchanged\nβœ… SDK methods work unchanged\nβœ… AI providers function correctly\nβœ… MCP tools continue working\n\nC.2 Performance Impact Testing (20 minutes)\n\nSuccess Criteria:\nβœ… Default performance unchanged\nβœ… Performance overhead \\<5% when features enabled\nβœ… Memory usage remains stable\nβœ… No performance regressions\n\nC.3 Real-World Scenario Testing (20 minutes)\n\nSuccess Criteria:\nβœ… WebSocket chat works end-to-end\nβœ… Telemetry collects accurate data\nβœ… Multi-provider scenarios work\nβœ… Streaming integrations functional\n\nβœ… PHASE D: FINAL VALIDATION (30 minutes)\n\nPriority: CRITICAL | Focus: Production readiness\n\nD.1 API Surface Validation (10 minutes)\n\nSuccess Criteria:\nβœ… All new exports importable\nβœ… TypeScript types correct\nβœ… No missing dependencies\nβœ… API surface consistent\n\nD.2 Documentation Synchronization (10 minutes)\n\nSuccess Criteria:\nβœ… Documentation reflects actual implementation\nβœ… Voice references removed/minimal\nβœ… New features documented\nβœ… Examples are accurate\n\nD.3 Production Deployment Readiness (10 minutes)\n\nSuccess Criteria:\nβœ… Package builds correctly\nβœ… Installation works\nβœ… Imports work after installation\nβœ… No missing files\nβœ… Ready for npm publish\n\nπŸ“Š SUCCESS CRITERIA SUMMARY\n\nCritical (Must Pass):\nβœ… Build Success: 0 TypeScript errors, successful compilation\nβœ… Backward Compatibility: All existing functionality works unchanged\nβœ… Performance: \\<5% overhead when new features disabled\nβœ… Voice AI Removal: No voice dependencies or code remaining\n\nImportant (Should Pass):\nβœ… WebSocket Infrastructure: Real-time services operational\nβœ… Telemetry Integration: Optional monitoring works when enabled\nβœ… Enhanced Chat: Dual-mode chat capabilities functional\nβœ… API Consistency: New exports and types work correctly\n\nNice to Have (Can Be Fixed):\nβœ… Documentation Completeness: All features documented\nβœ… Example Applications: Working demos available\nβœ… Performance Optimization: Further optimization opportunities\n\n🎯 EXECUTION ORDER\n\nSequential Execution Required:\nPhase A β†’ Mu","hierarchy":{"lvl0":"Development","lvl1":"πŸ§ͺ COMPREHENSIVE TESTING & VERIFICATION PLAN","lvl2":"","lvl3":""}},
@@ -2907,7 +2908,7 @@
2907
2908
  {"objectID":"8ea0d60b8e33eeebfb825eb12ad9fcd0cdad610ee262ac5486db5d7fa3b8406b","title":"5xx / Transient Server Error","url":"/docs/features/claude-proxy#5xx-transient-server-error","content":"Transient errors (408, 500, 502, 503, 504, and Cloudflare 520-526/529).\nAlso matches 400 responses with api_error or overloaded_error types that wrap transient HTML content (e.g., Cloudflare error pages).\nApply bounded same-account retries, then rotate to the next account.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy","lvl2":"5xx / Transient Server Error","lvl3":""}},
2908
2909
  {"objectID":"195dae3c0ea28fdcfeb0fbf39c456fd580652b07fa5f2ce81b341d4279621cf8","title":"All Accounts Exhausted","url":"/docs/features/claude-proxy#all-accounts-exhausted","content":"When every account is in a cooling state:\nWalk the fallback chain (if configured).\nEach fallback uses NeuroLink's stream() pipeline with the specified provider/model.\nIf all fallbacks also fail, return a 429 with Retry-After set to the earliest account recovery time.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy","lvl2":"All Accounts Exhausted","lvl3":""}},
2909
2910
  {"objectID":"a9d69b153d2a12e50877017c5bfbcdb2ba932f1223183c8c311614898ae4a910","title":"Bootstrap Retry (Streaming)","url":"/docs/features/claude-proxy#bootstrap-retry-streaming","content":"For streaming requests, the proxy reads the first chunk from the upstream response before forwarding it to the client. If the first chunk is empty (indicating a failed stream), the proxy retries with the next account. This prevents Claude Code from receiving an empty SSE stream.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy","lvl2":"Bootstrap Retry (Streaming)","lvl3":""}},
2910
- {"objectID":"98c795c3e6eec8f50fcb68adae0d6c62387d0ce83d06775eb4c32ff0698c7e7e","title":"Claude Code integration","url":"/docs/features/claude-proxy#claude-code-integration","content":"When the proxy starts, it automatically updates ~/.claude/settings.json:\n\nWhen the proxy stops (Ctrl+C or SIGTERM), it removes these entries from the settings file. This means Claude Code automatically routes through the proxy when it is running and goes direct when it is not.\n\nNote: You must restart Claude Code after starting or stopping the proxy for the settings change to take effect.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy","lvl2":"Claude Code integration","lvl3":""}},
2911
+ {"objectID":"98c795c3e6eec8f50fcb68adae0d6c62387d0ce83d06775eb4c32ff0698c7e7e","title":"Claude Code integration","url":"/docs/features/claude-proxy#claude-code-integration","content":"Foreground proxy start and explicit proxy setup configure ~/.claude/settings.json:\n\nWhen the proxy stops (Ctrl+C or SIGTERM), it removes these entries from the settings file. This means Claude Code automatically routes through the proxy when it is running and goes direct when it is not.\n\nNote: You must restart Claude Code after starting or stopping the proxy for the settings change to take effect.\n\nManaged service restarts and rolling upgrades preserve existing client settings.\nThey do not reapply routing or replace user edits. Run neurolink proxy setup\nwhen you want to configure clients explicitly, including after a standalone\nservice installation.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy","lvl2":"Claude Code integration","lvl3":""}},
2911
2912
  {"objectID":"228facfde8c5dd950496365bfc28e6470b20eee6543317f0c3cc9b5e239a972e","title":"Proxy state file","url":"/docs/features/claude-proxy#proxy-state-file","content":"The proxy persists its running state to ~/.neurolink/proxy-state.json so that neurolink proxy status can report on it and neurolink proxy start can detect an already-running instance. The state includes PID, port, host, strategy, start time, fallback chain, enforced account allowlist, and the optional foreground fail-open guard PID.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy","lvl2":"Proxy state file","lvl3":""}},
2912
2913
  {"objectID":"08047056092173a6d64c0fa57508b677157b3da499411f5a0783681010239ce9","title":"Fail-open guard","url":"/docs/features/claude-proxy#fail-open-guard","content":"A foreground proxy spawns one detached neurolink proxy guard that removes stale Claude Code settings after confirming its parent process has died. A launchd-managed proxy keeps restart ownership in launchd and starts a separate updater-only worker. Automatic package updates are enabled by default and can be disabled with NEUROLINK_PROXY_AUTO_UPDATE=off (also accepts 0 or false). The worker validates the global package root and executable directory and requires the package manager that owns the running installation. Rolling installations activate and health-check the new serving worker first. If the parent supervisor still reports the older version, the updater waits for a two-minute idle window, applies a bounded admission drain, and asks launchd to refresh the supervisor. Success requires both worker and supervisor to report the new version from a new parent process. The drain automatically expires if the updater disappears, and refresh failures retain the installed version for retry instead of repeatedly reinstalling it. Legacy services wait for every request and stream before their direct launchd restart. Post-install executable validation uses bounded retries, and the proxy supervises and replaces an updater worker that exits unexpectedly. Installed-but-not-running versions and stage-specific update failures remain persisted in ~/.neurolink/update-state.json. Updater diagnostics are sent through the configured proxy log sink and exposed in neurolink proxy status.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy","lvl2":"Fail-open guard","lvl3":""}},
2913
2914
  {"objectID":"778246a1bbbc0afc1258a50c9117e61d795099421fbd7f634d960f73aa6d3fc4","title":"Endpoints","url":"/docs/features/claude-proxy#endpoints","content":"| Method | Path | Description |\n| ------ | --------------------------- | --------------------------------------- |\n| POST | /v1/messages | Claude Messages API (main endpoint) |\n| GET | /v1/models | List available Claude models |\n| POST | /v1/messages/count_tokens | Token counting |\n| GET | /health | Health check (status, strategy, uptime) |\n| GET | /status | Detailed proxy status |","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy","lvl2":"Endpoints","lvl3":""}},
@@ -3369,7 +3370,7 @@
3369
3370
  {"objectID":"ac97e63916f0ffdf1d9befada357186f236753d40ea1f0e97bcab715e54fa7cd","title":"Relevance-driven compaction","url":"/docs/features/decide-inference-type#relevance-driven-compaction","content":"Before the existing positional compaction stages run, an optional Stage 0\nasks, per eligible message, whether the current request still needs it β€” at\n~400 ms for the whole batch regardless of message count (on TypeSafe;\nperplexity-decider differs, taking about 0.3 to 1.1 s for one question and about\n65 ms for each further one, plus an input time that grows faster than linearly\nwith size).\nOnly plain user/assistant text is eligible, the most recent messages are never\ntouched, and a message is dropped only on a confident \"no.\"\n\n| | Positional stages (1–4) | Stage 0 (relevance) |\n| ----------------- | ---------------------------------- | ------------------------------------------------------------ |\n| Basis for keeping | position (recency) | relevance to the current request |\n| Drop granularity | whole messages / summarized ranges | whole messages |\n| Runs when | always, once over budget | decision provider configured, request known, and over budget |\n\nSee relevance-driven compaction for\nthe eligibility rules, the drop cap, and the separate summary-quality gate on\nStage 3.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Relevance-driven compaction","lvl3":""}},
3370
3371
  {"objectID":"451d199b91f25696bed61dedb5ebc0465143dbf3bc350ca8a3943e622f9aedf8","title":"Tool / MCP routing","url":"/docs/features/decide-inference-type#tool-mcp-routing","content":"The shipped tool router asks a generative model for {servers: string[]} on\na 15-second budget β€” a shape that cannot express uncertainty. A decision\nmodel instead asks one yes/no question per server, answered with a probability,\nand a server is excluded only on a confident \"no\" (minDropConfidence default\n0.6), because dropping a needed server breaks the turn while keeping an unneeded\none only costs a few tokens.\n\nA measured wording change moved unrelated servers from a mean probability of\n0.31 (dropping 12 of 39 unneeded servers) to a mean of 0.03 (dropping 37 of\n39, with zero wrong drops) β€” seen in\ntool / MCP routing by decision model,\nwhich also covers the exact question shape and its size guards.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Tool / MCP routing","lvl3":""}},
3371
3372
  {"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":""}},
3372
- {"objectID":"6c0dd418b9f61219911960f90d1003a6c00c2e2cb81399ced3c885fd8209bc6e","title":"Limits and gotchas","url":"/docs/features/decide-inference-type#limits-and-gotchas","content":"Laya 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). So the\nprovider estimates the state's size β€” counting non-Latin characters at a rate\nmeasured per checkpoint β€” and refuses anything over the limit locally with\nmax_tokens_exceeded, before any network call. The estimate errs toward\nrefusing.\n\nXOR shares one prefill between the state, the questions and any media.\nNeuroLink allows about 200,000 estimated tokens of state (about four characters\nper token for ASCII, one token per character for other scripts) and refuses more\nlocally with max_tokens_exceeded. That figure is a conservative default under\nthe deployment's 250,000-token prefill, which the questions and any images or\nvideo also draw on; it has not been measured against a live deployment. A\nrequest that passes the local check can therefore still be refused by the\nserver as too long. That arrives as max_tokens_exceeded (not retried) when\nthe status is 413 or the message says the context was too long, and otherwise as\nserver, retried once. XOR has no question cap in NeuroLink, and its server takes 2 to 255\noptions on a choice or score.\n\nPerplexity's input ceiling covers more than the state. Measured on a real\naccount in October 2026: the server reads under 262,144 input tokens per request,\ncounted over the state and the questions, and refuses input of 262,144 tokens or\nmore with an explicit 400 instead of cutting the state off. Images are billed as\ninput tokens, about one for each 32 Γ— 32 tile plus about 95 for the image (a fit\nto three measured sizes), and are assumed to count toward the ceiling too; that\nwas not measured. It takes at most 128 questions and 8 images. The documented\n32 MiB body limit was not measured. NeuroLink's own window is 100,000 estimated\ntokens of state, a deliberate loc","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Limits and gotchas","lvl3":""}},
3373
+ {"objectID":"6c0dd418b9f61219911960f90d1003a6c00c2e2cb81399ced3c885fd8209bc6e","title":"Limits and gotchas","url":"/docs/features/decide-inference-type#limits-and-gotchas","content":"Laya 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). So the\nprovider estimates the state's size β€” counting non-Latin characters at a rate\nmeasured per checkpoint β€” and refuses anything over the limit locally with\nmax_tokens_exceeded, before any network call. The estimate errs toward\nrefusing.\n\nXOR shares one prefill between the state, the questions and any media.\nNeuroLink allows about 200,000 estimated tokens of state (about four characters\nper token for ASCII, one token per character for other scripts) and refuses more\nlocally with max_tokens_exceeded. That figure is a conservative default under\nthe deployment's 250,000-token prefill, which the questions and any images or\nvideo also draw on; it has not been measured against a live deployment. A\nrequest that passes the local check can therefore still be refused by the\nserver as too long. That arrives as max_tokens_exceeded (not retried) when\nthe status is 413 or the message says the context was too long, and otherwise as\nserver, retried once. XOR has no question cap in NeuroLink, and its server takes 2 to 255\noptions on a choice or score.\n\nPerplexity's input ceiling covers more than the state. Measured on a real\naccount in October 2026: the server reads under 262,144 input tokens per request,\ncounted over the state, the questions and the images, and refuses input of\n262,144 tokens or more with an explicit 400 instead of cutting the state off.\nImages are billed as input tokens, about one for each 32 Γ— 32 tile plus 95 to\n103 more in the single-image requests measured, which looks like fixed request\noverhead and not a charge per image. They count toward the ceiling at one token\nfor each tile: eight 2,048-tile images added 16,384 to a request that was then\nrefused. It takes at most 128 questions and 8","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Limits and gotchas","lvl3":""}},
3373
3374
  {"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\nTune thresholds on your own labelled data if the decision matters, and once you\nhave, pin TYPESAFE_MODEL to a version id such as jev-1.13.0 β€” jev-latest\nis an alias and can move under you, invalidating a tuned threshold silently.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"What it is bad at","lvl3":""}},
3374
3375
  {"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":""}},
3375
3376
  {"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":""}},
@@ -6873,24 +6874,24 @@
6873
6874
  {"objectID":"106d04b8baec018f872ce608c3b0dd33f8b3d43ada85072831a2e9ab9c64c46b","title":"Verification status","url":"/docs/getting-started/providers/pareto-inference#verification-status","content":"Tier-2 onboarding requires evidence before a provider is accepted, and\npnpm run verify:provider-onboarding gates it in CI. This is what the\ncatalog records for Pareto Inference β€” and, just as importantly, what it\ndoes not yet record:\n\n| Probe | Result |\n| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Roster | unauthenticated GET /v1/models, HTTP 200, 1 model (z-ai/glm-5.3-flash), 2026-09-28. No API key was used or required for this call. |\n| Auth rejection | Not probed. Would require a POST with an invalid key, which this credential-free onboarding pass does not send. Pareto's docs describe 401 as \"the chat API key is missing, invalid, or no longer active,\" with no example error body. |\n| Live capability sweep | Not run. evidence.liveMatrix is null. capabilities.tools and .thinking are set from the v","hierarchy":{"lvl0":"Getting Started","lvl1":"Pareto Inference Provider Guide","lvl2":"Verification status","lvl3":""}},
6874
6875
  {"objectID":"b844edaf09c93fb3089bbf0a71254c5039dedf111e2b59563321484496862aa4","title":"Troubleshooting","url":"/docs/getting-started/providers/pareto-inference#troubleshooting","content":"| Symptom | Cause | Fix |\n| --------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |\n| Invalid Pareto Inference API key | PARETO_INFERENCE_API_KEY unset, wrong, or expired | Pareto documents 401 as \"the chat API key is missing, invalid, or no longer active\" β€” check or replace the key in the dashboard |\n| 429 with credit_exhausted | Prepaid balance is empty | Buy more prepaid credits |\n| 429 with credit_insufficient | Held credits (reserved for max_tokens) are below what's needed | Lower max_tokens, or buy more credits |\n| 429 with model_capacity | The model itself is at capacity β€” not an account-level limit | Honor the Retry-After header and retry |\n| 502 mid-stream | The model request failed after the stream started | Retry the request; check whether a tool call already ran before retrying |\n| 503 | Temporary Pareto-side failure (e.g. maintenance, GPU outage) | Wait and retry; Retry-After gives the delay in seconds |\n| No context-window figure in the catalog | Pareto does no","hierarchy":{"lvl0":"Getting Started","lvl1":"Pareto Inference Provider Guide","lvl2":"Troubleshooting","lvl3":""}},
6875
6876
  {"objectID":"57b8457eff592f229d3c0f0fb7c73148341ecffd72bb29c15d73f1471b1fd886","title":"See also","url":"/docs/getting-started/providers/pareto-inference#see-also","content":"Provider setup overview\nAll providers\nTier-2 onboarding β€” how this provider's JSON becomes a working integration\nProvider feature compatibility","hierarchy":{"lvl0":"Getting Started","lvl1":"Pareto Inference Provider Guide","lvl2":"See also","lvl3":""}},
6876
- {"objectID":"daf00919862e4bbed4b3fc1082bea17843a987e5e3970cefed2c95537b22cceb","title":"Perplexity Decisions Provider Guide","url":"/docs/getting-started/providers/perplexity-decider","content":"Perplexity Decisions Provider Guide\n\nA provider of decide β€” the same typed boolean / choice / score\nanswers as TypeSafe's Jev, Laya and XOR,\nfrom Perplexity's hosted Decisions API, and it also reads images. It emits no\ntext at all.\n\nThis is not the Perplexity text provider (perplexity, the\nSonar models), which serves generate() and stream(). The two share one API\nkey, which has a consequence worth reading before you set it. See\nWhat is sent to Perplexity and\nOne key, two providers.\n\nOverview\n\npplx-decider-v1-27b is Perplexity's decision model. You send one state\nplus named, typed questions, and optionally images. The model answers every\nquestion in a single batched pass and returns a typed answer for each, with a\nprobability instead of a sentence. NeuroLink calls Perplexity's public endpoint,\nso a key alone configures it: there is no base URL to set.\n\nKey Facts\n\n| | |\n| ------------------------ | ----------------------------------------------------------------------------------------------------------------- |\n| Provider id | perplexity-decider (no aliases) β€” distinct from perplexity, the Sonar text provider |\n| Inference type | decide only |\n| Model | pplx-decider-v1-27b; the API answers 400 to a missing or unknown model. PERPLEXITY_DECIDER_MODEL sets it |\n| Key | PERPLEXITY_API_KEY, shared with the Perplexity text provider, or credentials.perplexityDecider.apiKey |\n| Endpoint | https://api.perplexity.ai/v1/decisions; PERPLEXITY_DECIDER_BASE_URL can name another origin |\n| Media | images (PNG, JPEG or WebP), up to 8 per request; no video |\n| Questions per request | up to 128 |\n| Server input ceiling | under 262,144 tokens (state and questions); more is refused with an explicit 400, never cut off silently |\n| Images and that ceiling | billed as input tokens (measured); that they count toward the ceiling is assumed, not measured |\n| NeuroLink's state window | 100,000 estimated tokens: a deliberate local limit, not the server's |\n| Cost | $0.04 per million input tokens (image tokens included); output tokens are free. Perplexity's documented price |\n| Default timeout | 10 seconds plus 100 ms for each question (10.1 s for one, 22.8 s for 128); timeoutMs or --timeout replaces it |\n| Precedence | used automatically when TypeSafe, Laya and XOR are not configured |\n\nEach limit, token rate and latency in this guide is either measured on a real\naccount in October 2026 or taken from Perplexity's documentation, and says\nwhich where it appears. Measured: the 128-question and 8-image caps, the\n262,144-token input ceiling for the state and the questions (nothing is cut off\nsilently), characters per token for each kind of text, latency by input size and\nby question count, what an image costs, which image sizes stall, and how the API\nanswers a burst of requests. Documented and not tested: the 32 MiB request body,\nthe price, and the option and level counts. Perplexity documents a limit of 10\nrequests per second for the account's tier (every organization, on every plan,\nwith a token limit on large bursts), and a burst test on the one account tested\nsaw the request limit act. The 2,048-tile image rule is Perplexity's documented\nrule, checked at three image sizes (see Images). One thing is assumed,\nnot measured: that images count toward the 262,144-token ceiling. They are billed\nas input tokens, which was measured, but no request put images next to the\nceiling.\n\nQuick Start\nGet a key\n\nCreate one in the Perplexity console. Any\nPerplexity API key works.\nConfigure\n\nSet the key in the environment:\n\nor in the config passed to the SDK, exactly as for any other provider. Values\npassed per call override the constructor's, which override the environment:\n\ncredentials.perplexityDecider is its own slice. A key passed as\ncredentials.perplexity belongs to the text provider and does not configure\nthis one. PERPLEXITY_BASE_URL, which moves the text provider, is not read here;\nthe override for this provider is PERPLEXITY_DECIDER_BASE_URL, and a trailing\n/v1 on it is accepted.\nUse it\n\nNeuroLink's boolean question is sent to the API as its noul type, and the\nanswer is read back as a boolean. A boolean answer carries a probability and\nno confidence of its own; a choice or score answer carries the confidence the\nAPI reports, which ","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"","lvl3":""}},
6877
+ {"objectID":"daf00919862e4bbed4b3fc1082bea17843a987e5e3970cefed2c95537b22cceb","title":"Perplexity Decisions Provider Guide","url":"/docs/getting-started/providers/perplexity-decider","content":"Perplexity Decisions Provider Guide\n\nA provider of decide β€” the same typed boolean / choice / score\nanswers as TypeSafe's Jev, Laya and XOR,\nfrom Perplexity's hosted Decisions API, and it also reads images. It emits no\ntext at all.\n\nThis is not the Perplexity text provider (perplexity, the\nSonar models), which serves generate() and stream(). The two share one API\nkey, which has a consequence worth reading before you set it. See\nWhat is sent to Perplexity and\nOne key, two providers.\n\nOverview\n\npplx-decider-v1-27b is Perplexity's decision model. You send one state\nplus named, typed questions, and optionally images. The model answers every\nquestion in a single batched pass and returns a typed answer for each, with a\nprobability instead of a sentence. NeuroLink calls Perplexity's public endpoint,\nso a key alone configures it: there is no base URL to set.\n\nKey Facts\n\n| | |\n| ------------------------ | ----------------------------------------------------------------------------------------------------------------- |\n| Provider id | perplexity-decider (no aliases) β€” distinct from perplexity, the Sonar text provider |\n| Inference type | decide only |\n| Model | pplx-decider-v1-27b; the API answers 400 to a missing or unknown model. PERPLEXITY_DECIDER_MODEL sets it |\n| Key | PERPLEXITY_API_KEY, shared with the Perplexity text provider, or credentials.perplexityDecider.apiKey |\n| Endpoint | https://api.perplexity.ai/v1/decisions; PERPLEXITY_DECIDER_BASE_URL can name another origin |\n| Media | images (PNG, JPEG or WebP), up to 8 per request; no video |\n| Questions per request | up to 128 |\n| Server input ceiling | under 262,144 tokens (state, questions and images); more is refused with an explicit 400, never cut off silently |\n| Images and that ceiling | billed as input tokens, and counted toward the ceiling at one token per 32 Γ— 32 tile (measured) |\n| NeuroLink's state window | 100,000 estimated tokens: a deliberate local limit, not the server's |\n| Cost | $0.04 per million input tokens (image tokens included); output tokens are free. Perplexity's documented price |\n| Default timeout | 10 seconds plus 100 ms for each question (10.1 s for one, 22.8 s for 128); timeoutMs or --timeout replaces it |\n| Precedence | used automatically when TypeSafe, Laya and XOR are not configured |\n\nEach limit, token rate and latency in this guide is either measured on a real\naccount in October 2026 or taken from Perplexity's documentation, and says\nwhich where it appears. Measured: the 128-question and 8-image caps, the\n262,144-token input ceiling for the state, the questions and the images (nothing\nis cut off silently), characters per token for each kind of text, latency by\ninput size and by question count, what an image costs, which image sizes stall\n(the 2,048-tile rule, checked at its edge: see Images), and how the\nAPI answers a burst of requests. Documented and not tested: the 32 MiB request\nbody, the price, and the option and level counts. Perplexity documents a limit of\n10 requests per second for the account's tier (every organization, on every\nplan, with a token limit on large bursts), and a burst test on the one account\ntested saw the request limit act.\n\nQuick Start\nGet a key\n\nCreate one in the Perplexity console. Any\nPerplexity API key works.\nConfigure\n\nSet the key in the environment:\n\nor in the config passed to the SDK, exactly as for any other provider. Values\npassed per call override the constructor's, which override the environment:\n\ncredentials.perplexityDecider is its own slice. A key passed as\ncredentials.perplexity belongs to the text provider and does not configure\nthis one. PERPLEXITY_BASE_URL, which moves the text provider, is not read here;\nthe override for this provider is PERPLEXITY_DECIDER_BASE_URL, and a trailing\n/v1 on it is accepted.\nUse it\n\nNeuroLink's boolean question is sent to the API as its noul type, and the\nanswer is read back as a boolean. A boolean answer carries a probability and\nno confidence of its own; a choice or score answer carries the confidence the\nAPI reports, which Perplexity describes as the model's own certainty estimate,\nnot the top probability. Perplexity's API reference and quickstart do not call\nthat confidence calibrated, and NeuroLink did not measure whether it is, so tune\na t","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"","lvl3":""}},
6877
6878
  {"objectID":"cd579839c9ecb7a84dee24ccd591e76f90eb1f05b384a35488c7603f72178d38","title":"Perplexity Decisions Provider Guide","url":"/docs/getting-started/providers/perplexity-decider#perplexity-decisions-provider-guide","content":"A provider of decide β€” the same typed boolean / choice / score\nanswers as TypeSafe's Jev, Laya and XOR,\nfrom Perplexity's hosted Decisions API, and it also reads images. It emits no\ntext at all.\n\nThis is not the Perplexity text provider (perplexity, the\nSonar models), which serves generate() and stream(). The two share one API\nkey, which has a consequence worth reading before you set it. See\nWhat is sent to Perplexity and\nOne key, two providers.","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Perplexity Decisions Provider Guide","lvl3":""}},
6878
6879
  {"objectID":"0d2eec9390e1cc5078e5419138c190cc8dc524c5ebd8972a9c7afa9625dae43a","title":"Overview","url":"/docs/getting-started/providers/perplexity-decider#overview","content":"pplx-decider-v1-27b is Perplexity's decision model. You send one state\nplus named, typed questions, and optionally images. The model answers every\nquestion in a single batched pass and returns a typed answer for each, with a\nprobability instead of a sentence. NeuroLink calls Perplexity's public endpoint,\nso a key alone configures it: there is no base URL to set.","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Overview","lvl3":""}},
6879
- {"objectID":"c9690ba724ce4205d66ac4d75981884b735170b152767047afcc0d406d5e7c8d","title":"Key Facts","url":"/docs/getting-started/providers/perplexity-decider#key-facts","content":"| | |\n| ------------------------ | ----------------------------------------------------------------------------------------------------------------- |\n| Provider id | perplexity-decider (no aliases) β€” distinct from perplexity, the Sonar text provider |\n| Inference type | decide only |\n| Model | pplx-decider-v1-27b; the API answers 400 to a missing or unknown model. PERPLEXITY_DECIDER_MODEL sets it |\n| Key | PERPLEXITY_API_KEY, shared with the Perplexity text provider, or credentials.perplexityDecider.apiKey |\n| Endpoint | https://api.perplexity.ai/v1/decisions; PERPLEXITY_DECIDER_BASE_URL can name another origin |\n| Media | images (PNG, JPEG or WebP), up to 8 per request; no video |\n| Questions per request | up to 128 |\n| Server input ceiling | under 262,144 tokens (state and questions); more is refused with an explicit 400, never cut off silently |\n| Images and that ceiling | billed as input tokens (measured); that they count toward the ceiling is assumed, not measured |\n| NeuroLink's state window | 100,000 estimated tokens: a deliberate local limit, not the server's |\n| Cost | $0.04 per million input tokens (image tokens included); output tokens are free. Perplexity's documented price |\n| Default timeout | 10 seconds plus 100 ms for each question (10.1 s for one, 22.8 s for 128); timeoutMs or --timeout replac","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Key Facts","lvl3":""}},
6880
+ {"objectID":"c9690ba724ce4205d66ac4d75981884b735170b152767047afcc0d406d5e7c8d","title":"Key Facts","url":"/docs/getting-started/providers/perplexity-decider#key-facts","content":"| | |\n| ------------------------ | ----------------------------------------------------------------------------------------------------------------- |\n| Provider id | perplexity-decider (no aliases) β€” distinct from perplexity, the Sonar text provider |\n| Inference type | decide only |\n| Model | pplx-decider-v1-27b; the API answers 400 to a missing or unknown model. PERPLEXITY_DECIDER_MODEL sets it |\n| Key | PERPLEXITY_API_KEY, shared with the Perplexity text provider, or credentials.perplexityDecider.apiKey |\n| Endpoint | https://api.perplexity.ai/v1/decisions; PERPLEXITY_DECIDER_BASE_URL can name another origin |\n| Media | images (PNG, JPEG or WebP), up to 8 per request; no video |\n| Questions per request | up to 128 |\n| Server input ceiling | under 262,144 tokens (state, questions and images); more is refused with an explicit 400, never cut off silently |\n| Images and that ceiling | billed as input tokens, and counted toward the ceiling at one token per 32 Γ— 32 tile (measured) |\n| NeuroLink's state window | 100,000 estimated tokens: a deliberate local limit, not the server's |\n| Cost | $0.04 per million input tokens (image tokens included); output tokens are free. Perplexity's documented price |\n| Default timeout | 10 seconds plus 100 ms for each question (10.1 s for one, 22.8 s for 128); timeoutMs or --timeout replac","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Key Facts","lvl3":""}},
6880
6881
  {"objectID":"467fb7efd250abc71afba6a9535ee164e671526dc06ff59407a827bda872b268","title":"1. Get a key","url":"/docs/getting-started/providers/perplexity-decider#1-get-a-key","content":"Create one in the Perplexity console. Any\nPerplexity API key works.","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"1. Get a key","lvl3":""}},
6881
6882
  {"objectID":"bd7509f708e016023be201690ca4cc963bc77551d7152b34c636ae628ea5e497","title":"2. Configure","url":"/docs/getting-started/providers/perplexity-decider#2-configure","content":"Set the key in the environment:\n\nor in the config passed to the SDK, exactly as for any other provider. Values\npassed per call override the constructor's, which override the environment:\n\ncredentials.perplexityDecider is its own slice. A key passed as\ncredentials.perplexity belongs to the text provider and does not configure\nthis one. PERPLEXITY_BASE_URL, which moves the text provider, is not read here;\nthe override for this provider is PERPLEXITY_DECIDER_BASE_URL, and a trailing\n/v1 on it is accepted.","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"2. Configure","lvl3":""}},
6882
6883
  {"objectID":"c3dbe3c712926dfb07b0d907370532df8bc3c98a5e81f4b46784a037ac0f1e0b","title":"3. Use it","url":"/docs/getting-started/providers/perplexity-decider#3-use-it","content":"NeuroLink's boolean question is sent to the API as its noul type, and the\nanswer is read back as a boolean. A boolean answer carries a probability and\nno confidence of its own; a choice or score answer carries the confidence the\nAPI reports, which Perplexity describes as the model's own certainty estimate,\nnot the top probability. Perplexity's API reference and quickstart do not call\nthat confidence calibrated, and NeuroLink did not measure whether it is, so tune\na threshold on it against your own labelled data. (The Hugging Face model card\nfor the open-weights model describes its output as calibrated probabilities.)\nPerplexity also notes that identical requests occasionally differ in the second\ndecimal place. Repeating a request returned the same numbers in NeuroLink's\nprobe, but leave some margin when you set a threshold anyway.","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"3. Use it","lvl3":""}},
6883
6884
  {"objectID":"6f3f0a67d6c85ce65d1d7d95a7016987ad0423b545c9f849bcde853edd0dd20f","title":"From the CLI","url":"/docs/getting-started/providers/perplexity-decider#from-the-cli","content":"The CLI reads the same environment variables:\n\nThe text output ends with a Cost: line, priced from the input tokens the API\nreports.","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"From the CLI","lvl3":""}},
6884
- {"objectID":"e1b9161659de68a10277e69ce53077f2aed241892d783054f01471fb793024bd","title":"Images","url":"/docs/getting-started/providers/perplexity-decider#images","content":"Perplexity reads images alongside the state. TypeSafe and Laya do not read\nmedia. XOR reads images and a video; Perplexity reads images only. In the probe\nthe model did read an image: asked red versus blue about one, it answered\ncorrectly at about 0.98 confidence.\n\nFrom the CLI, pass --image <path>, repeated for several:\n\nOn the wire the images go inside state: NeuroLink sends state as an array,\nyour state first and then one OpenAI-style image_url part per image, each a\nbase64 data URL. The API has no separate images field and rejects unknown\nfields. An image can also be the whole input (an image-only state was\naccepted in the probe); from the SDK, pass an empty string as state with\nimages. The CLI always needs a state.\n\nThe rules:\nUp to 8 images per request. Measured: 8 images with three questions were\n accepted, and 9 images with one question were refused with a 400 whose message\n words the cap as \"per question\". NeuroLink applies the 8 to the request as a\n whole.\nPNG, JPEG or WebP only. The type comes from the bytes, not the file\n extension. A GIF, or a data: URL of another type, is refused before any\n request, as a non-retryable invalid_request. The API refuses a GIF with a 400\n too.\nEach is a Buffer, a local file path or a data: URL. An http(s) URL is\n refused locally and never fetched. The API does not fetch URLs either: an\n https image URL returned a 400 in the probe.\nEach image may be at most 2,048 tiles of 32 Γ— 32 pixels. Round the width\n and the height to the nearest multiple of 32 and keep (width / 32) Γ—\n (height / 32) at or under 2,048: by that count 1440 Γ— 1440 (2,025 tiles) and\n 2048 Γ— 1024 (2,048) fit, and 1600 Γ— 1310 (2,050) does not. Perplexity documents\n this rule. The probe tried three sizes, and all three agree with it:\n 1920 Γ— 1080 (2,040 tiles) was answered in 1.1 seconds, while 2048 Γ— 2048\n (4,096 tiles, tried twice) and 4000 Γ— 3000 (11,750 tiles) stalled for about\n 56 seconds and came back as an HTML 504. No size just past the ","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Images","lvl3":""}},
6885
+ {"objectID":"e1b9161659de68a10277e69ce53077f2aed241892d783054f01471fb793024bd","title":"Images","url":"/docs/getting-started/providers/perplexity-decider#images","content":"Perplexity reads images alongside the state. TypeSafe and Laya do not read\nmedia. XOR reads images and a video; Perplexity reads images only. In the probe\nthe model did read an image: asked red versus blue about one, it answered\ncorrectly at about 0.98 confidence.\n\nFrom the CLI, pass --image <path>, repeated for several:\n\nOn the wire the images go inside state: NeuroLink sends state as an array,\nyour state first and then one OpenAI-style image_url part per image, each a\nbase64 data URL. The API has no separate images field and rejects unknown\nfields. An image can also be the whole input (an image-only state was\naccepted in the probe); from the SDK, pass an empty string as state with\nimages. The CLI always needs a state.\n\nThe rules:\nUp to 8 images per request. Measured: 8 images with three questions were\n accepted, and 9 images with one question were refused with a 400 whose message\n words the cap as \"per question\". NeuroLink applies the 8 to the request as a\n whole.\nPNG, JPEG or WebP only. The type comes from the bytes, not the file\n extension. A GIF, or a data: URL of another type, is refused before any\n request, as a non-retryable invalid_request. The API refuses a GIF with a 400\n too.\nEach is a Buffer, a local file path or a data: URL. An http(s) URL is\n refused locally and never fetched. The API does not fetch URLs either: an\n https image URL returned a 400 in the probe.\nEach image may be at most 2,048 tiles of 32 Γ— 32 pixels. Round the width\n and the height to the nearest multiple of 32 and keep (width / 32) Γ—\n (height / 32) at or under 2,048: by that count 1440 Γ— 1440 (2,025 tiles) and\n 2048 Γ— 1024 (2,048) fit, and 1600 Γ— 1310 (2,050) does not. Perplexity documents\n this rule, and it was checked at its edge. Fitting sizes were answered in\n about a second: 1920 Γ— 1080 (2,040 tiles) in 1.1 seconds, 2048 Γ— 1024 (2,048,\n exactly the cap) in 1.3 and 1450 Γ— 1450 in 1.1. That last one rounds to 45 tiles\n a side (45.3), 2,025 in all, where rounding up (","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Images","lvl3":""}},
6885
6886
  {"objectID":"8ad813ca01099f441bbc2db40ee064d9a0294d269166c42a6f87fce2a1c1330f","title":"When NeuroLink uses it","url":"/docs/getting-started/providers/perplexity-decider#when-neurolink-uses-it","content":"Every built-in consumer of decide asks for the default decision provider. That\nis the first one that is configured, in the environment or in the credentials\npassed to the SDK, in the order TypeSafe, Laya, XOR, Perplexity. TypeSafe counts\nwith either of its keys, TYPESAFE_API_KEY or AI_GATEWAY_API_KEY. Laya and XOR\neach count only with both their key and their base URL. Perplexity counts with\nits key alone, a non-blank PERPLEXITY_API_KEY or\ncredentials.perplexityDecider.apiKey. A caller can always name it with\nprovider: \"perplexity-decider\". So:\nOnly a Perplexity key: built-in features use Perplexity.\nA Perplexity key, plus TypeSafe's key, or Laya's or XOR's key and base\n URL: built-in features use TypeSafe, Laya or XOR, in that order, whichever\n is configured. Perplexity runs only where a caller asks for\n provider: \"perplexity-decider\".\nA key for the text provider only: the same as the first case. The key is\n shared, so the text provider's key also configures this one. See\n One key, two providers.\nNone of TypeSafe, Laya, XOR or Perplexity configured: everything behaves\n exactly as it did without a decision model.\n\nThe classifier router's auto gate reads the credentials given to the\nNeuroLink constructor and the environment, not credentials passed on a single\ncall, so a per-call credentials.perplexityDecider does not influence it. The\nother consumers NeuroLink wires itself (compaction and tool routing) call\ntryDecide without credentials too.\n\nWhere the built-in consumers use the default provider (what each one sends is\nlisted in What is sent to Perplexity):\n\n| Area | What the decision replaces |\n| ---------------------------------------------------------------- | --------------------------------------------------------------- |\n| Model routing | difficulty + capabilities + risk + model pick in one round trip |\n| Model catalogue | one choice over the registry ","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"When NeuroLink uses it","lvl3":""}},
6886
6887
  {"objectID":"9545ac1f3da9bfc59774adf1978baa598ba4fc65670b5d0d4c96f7c10e2a1c3c","title":"What is sent to Perplexity","url":"/docs/getting-started/providers/perplexity-decider#what-is-sent-to-perplexity","content":"Perplexity receives the state and the questions of every decision made on\nyour behalf. 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.\nSends: the generated summary (first 12,000 characters) and the last 60\n m","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"What is sent to Perplexity","lvl3":""}},
6887
6888
  {"objectID":"01342235e59d6796c886025eea6c3dbdefc5f4420f47123db9b23eacc22955d3","title":"One key, two providers","url":"/docs/getting-started/providers/perplexity-decider#one-key-two-providers","content":"PERPLEXITY_API_KEY is the variable the\nPerplexity text provider reads to serve generate() and\nstream(). It is also the variable that configures this provider. Nothing else\nneeds to be set, so a host that set the key only to use Sonar has also\nconfigured decide:\nWith none of TypeSafe, Laya or XOR configured, the texts listed in\n What is sent to Perplexity go to Perplexity's\n Decisions API. Context compaction needs no other opt-in, so a host with long\n conversations starts sending conversation text the first time one outgrows its\n budget. Model routing, tool routing and RAG planning do so only where you have\n turned them on. No code changes: the key is the switch.\nIt is fail-open, and TypeSafe, Laya and XOR take precedence. If you have\n configured any of them, the shared key changes nothing for the built-in\n consumers, and a Perplexity failure leaves behaviour as it was.\nWith no decision provider configured at all, nothing is sent.\n\nAn unedited copy of .env.example does not set the key, because its\nPERPLEXITY_API_KEY line is commented out.\n\nA key in a .env file counts as a key in the environment. Importing the SDK\nloads the .env in the current working directory, and the CLI does the same at\nstart; when DOTENV_CONFIG_PATH is set, that file is loaded instead. A key that\nsits in .env therefore configures decide exactly as one exported in the\nshell does.\n\nTo keep a key that was set for Sonar from activating decisions, use one of\nthese:\nHand the key to the text provider through the SDK, not the environment, and\n keep it out of .env.\n new NeuroLink({ credentials: { perplexity: { apiKey } } }) configures the\n text provider and not this one, because NeuroLink looks for this provider's\n key in PERPLEXITY_API_KEY and in credentials.perplexityDecider, never in\n credentials.perplexity. The key must also be absent from .env: remove the\n PERPLEXITY_API_KEY line from that file as well as from the shell, or point\n DOTENV_CONFIG_PATH at a file that does not have i","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"One key, two providers","lvl3":""}},
6888
- {"objectID":"2c9da95e9403e04ac92a64727b9b098a3b1e626742b59f4ffebc6e24914ec316","title":"Measured on a real account, October 2026","url":"/docs/getting-started/providers/perplexity-decider#measured-on-a-real-account-october-2026","content":"NeuroLink probed the live API from an account limited to 10 requests per second.\nThese figures were observed, not taken from Perplexity's documentation:\n\n| What | Measured |\n| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Questions per request | 128 accepted (128 answers in 8.9 s, 11,904 input tokens); 129 is refused with a 400. An extra minimal question adds about 92 input tokens, and a one-character state with one question bills 116. |\n| Images per request | 8 accepted (with three questions); 9 refused with a 400 (with one question; the message says \"per question\"). ","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Measured on a real account, October 2026","lvl3":""}},
6889
+ {"objectID":"2c9da95e9403e04ac92a64727b9b098a3b1e626742b59f4ffebc6e24914ec316","title":"Measured on a real account, October 2026","url":"/docs/getting-started/providers/perplexity-decider#measured-on-a-real-account-october-2026","content":"NeuroLink probed the live API from an account limited to 10 requests per second.\nThese figures were observed, not taken from Perplexity's documentation:\n\n| What | Measured |\n| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| Questions per request | 128 accepted (128 answers in 8.9 s, 11,904 input tokens); 129 is refused with a 400. An extra minimal question adds about 92 input tokens, and a one-character state with one question bills 116. ","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Measured on a real account, October 2026","lvl3":""}},
6889
6890
  {"objectID":"bb716df9ef27b597327dd3b40f9b5429c5e7d66e789cc5d677574fa3f3fea651","title":"What Perplexity documents and the probe did not check","url":"/docs/getting-started/providers/perplexity-decider#what-perplexity-documents-and-the-probe-did-not-check","content":"The request body: 32 MiB, refused with a 413.\nNames, options and levels: every question needs a non-empty name; 1 to 255\n options on a choice; 1 to 10 levels on a score.\nThe price: $0.04 per million input tokens, image tokens included, output\n free.\nThe rate: 10 requests per second for the account's tier, and a token limit\n that also applies to large bursts; either answers 429. The burst test above saw\n the request limit act on the one account tested, and the token limit was not\n tested.\nNot verified: the status the API returns for an account with no credit. A\n key with no balance could not be created for the probe. Whatever comes back is\n classified by the table under Errors: a 401 disables the provider\n instance, a 429 is retried once, and any other 4xx is an invalid_request.","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"What Perplexity documents and the probe did not check","lvl3":""}},
6890
6891
  {"objectID":"12d235ff87ac1a95fdf64d56f736e5bd5c986e271ceb4dfd014e03572ee1290c","title":"What NeuroLink refuses before any request","url":"/docs/getting-started/providers/perplexity-decider#what-neurolink-refuses-before-any-request","content":"These are NeuroLink's own limits, set from the measurements above. A request\nover any of them fails locally, with no network call, and every built-in\nconsumer treats that as \"carry on as before\".\nA state estimated above 100,000 tokens is refused with\n max_tokens_exceeded. The window is a deliberate local limit, not a server\n limit: the server reads up to 262,144 tokens in all. It is set lower because\n latency grows faster than linearly with input (3.9 s at 65,000 tokens, 10 s at\n 146,000), so a state of 100,000 tokens takes about 7 seconds of the 10-second\n allowance, an interpolation between those two measurements and not a\n measurement of its own, and a much larger one would likely time out and be\n retried into the same wait. The estimate is 3.81 characters per token for\n ASCII text (four, with a 5% margin), which is about 381,000 characters at the\n window, and half a token per non-ASCII character, near the measured rate for\n CJK (about 0.46) and Devanagari (0.44). It covers the text of the state only,\n not the questions or the images.\nThe estimate is a guard, not a promise of acceptance. Against the measured\n characters per token, it over-counts English prose (4.34) and is close for\n TypeScript (3.84). It under-counts minified JSON (3.36) by about 13%, which\n does not matter at the window: 380,000 characters of JSON, estimated at 100,000\n tokens, are about 113,000 real tokens, far under the 262,144 the server reads.\n Log lines (1.35) are under-counted by about 2.8 times and arrays of integers\n (1.16) by about 3.3 times, and a state of either kind can pass the window and\n still be refused by the server for being over its ceiling: 380,000 characters\n of log lines are about 281,000 real tokens, and of integer arrays about\n 328,000. Text that is mostly emoji (2.6 tokens per code point, against the half\n token it charges) can be refused the same way. That refusal is reported as\n max_tokens_exceeded too, and is not retried.\nA state estimated above","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"What NeuroLink refuses before any request","lvl3":""}},
6891
6892
  {"objectID":"8e97b6f8092812014ba072ae65457308bc11e5c8b5349d31ff466c7db1f9cb39","title":"Latency and the timeout","url":"/docs/getting-started/providers/perplexity-decider#latency-and-the-timeout","content":"The default timeout is 10 seconds plus 100 ms for each question: 10.1\nseconds for one question and 22.8 seconds for the 128-question maximum. A\ntimeoutMs you pass, or --timeout on the CLI, is used exactly as given, with\nnothing added. The 10 seconds are the allowance for reading the input. Latency\ngrows faster than linearly with input (3.9 s at 65,000 tokens, 10 s at 146,000\nand 22.9 s at 251,000), so a state of 100,000 tokens takes about 7 s, an\ninterpolation between the 65,000- and 146,000-token measurements, and a larger\none needs a larger timeoutMs. The 100 ms follows what a question costs: each\none after the first added about 65 ms, and 128 minimal questions took 8.9 s on\n11,904 input tokens, so a flat 10 seconds would have been nearly spent on the\nquestions alone. Images count as input tokens too (see Images).\n\nA timeout is retried once, so a request that stalls can take about twice the\ntimeout plus a quarter to half a second before it fails: about 20 seconds at the\ndefault for one question. Pass a larger timeoutMs for a state of more than\nabout 100,000 real tokens, which log lines and arrays of numbers reach well\ninside the window (see\nWhat NeuroLink refuses). A model\nthat does not answer in time returns an HTML 504 after about a minute;\nNeuroLink's shorter timeout fires first, so it arrives as timeout, retried\nonce.\n\nEach built-in consumer takes its timeout from where it is configured:\nModel routing (with the model catalogue and the context budget, which share\n its request): classifierRouter.timeoutMs in the NeuroLink config, passed to\n the decision request when set.\nRelevance compaction: contextRelevance.timeoutMs in the NeuroLink\n config.\nSummary-quality gate: no setting. The NeuroLink config has none for it.\nTool / MCP routing: no setting for the decision request.\n toolRouting.timeoutMs bounds the generative router only.\nRAG planning: no setting in the pipeline config. The pipeline calls the\n decide function you give it, so set timeoutMs in the call ","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Latency and the timeout","lvl3":""}},
6892
6893
  {"objectID":"e0c0e895220d617b9c97e379206986672c638c01de25fb9e0b52fa7c04bf0ca1","title":"Rate limits","url":"/docs/getting-started/providers/perplexity-decider#rate-limits","content":"The account measured allows 10 requests per second. A 429 is retried once, after\nthe wait its Retry-After header asks for. NeuroLink honours that header on any\nretried reply that carries it, and only as a whole number of seconds above zero\nor as an HTTP date in the future; anything else (zero, a negative number, a hex\nor exponent spelling, a fraction, a date already past) is ignored, and the\ndefault backoff of a quarter to half a second is used instead. A wait longer\nthan what is left of the attempt's timeout is not taken: the error is thrown at\nonce so a fail-open consumer is not held for the length of a cooldown, and a\ncaller's abort signal ends a wait immediately.","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Rate limits","lvl3":""}},
6893
- {"objectID":"f40b2da5feaf02bc4eaf5102d75c33ce6fc9f979f7106853002b142aad4fd67f","title":"Errors","url":"/docs/getting-started/providers/perplexity-decider#errors","content":"| Reply | Kind | Retried |\n| ------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------ |\n| 401 | authentication β€” the provider instance stops retrying | no |\n| 413 | max_tokens_exceeded (the body is over 32 MiB) | no |\n| 400 saying the input exceeds or equals the model's maximum context length | max_tokens_exceeded | no |\n| any other 4xx (for example another 400, 403, 404) | invalid_request, with Perplexity's own message | no |\n| 429 | rate_limit | yes, once, after Retry-After |\n| 503 | overloaded | yes, once |\n| other 5xx (500, 502, 504) | server | yes, once |\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 ","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Errors","lvl3":""}},
6894
+ {"objectID":"f40b2da5feaf02bc4eaf5102d75c33ce6fc9f979f7106853002b142aad4fd67f","title":"Errors","url":"/docs/getting-started/providers/perplexity-decider#errors","content":"| Reply | Kind | Retried |\n| -------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------ |\n| 401 | authentication β€” the provider instance stops retrying | no |\n| 413 | max_tokens_exceeded (the body is over 32 MiB) | no |\n| 400 saying the input exceeds the model's maximum context length | max_tokens_exceeded | no |\n| any other 4xx (for example another 400, 403, 404) | invalid_request, with Perplexity's own message | no |\n| 429 | rate_limit | yes, once, after Retry-After |\n| 503 | overloaded | yes, once |\n| other 5xx (500, 502, 504) | server | yes, once |\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| state or questions over the limit (local) ","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Errors","lvl3":""}},
6894
6895
  {"objectID":"a812289efc882316bb62c31aea533cd0a0e8e219eeea12289b4503450b4dd9a5","title":"Troubleshooting","url":"/docs/getting-started/providers/perplexity-decider#troubleshooting","content":"Perplexity requires an API key β€” set PERPLEXITY_API_KEY, or pass\n credentials.perplexityDecider.apiKey. A key passed as\n credentials.perplexity does not count.\nA 401, Invalid API key provided β€” Perplexity rejected the key, and it\n checks the key before anything else. The provider instance stops retrying\n after a rejection, so fix the key and construct a new one.\nA 400 naming the model β€” PERPLEXITY_DECIDER_MODEL, or a per-call\n model, names something other than pplx-decider-v1-27b.\nThe Perplexity base URL must not carry credentials… β€” the override has a\n user name, a password, a query string or a fragment. Set it to the origin only,\n or leave it unset for https://api.perplexity.ai.\nThe Perplexity base URL must start with https:// or http:// β€” the value\n parses as a URL with another scheme: an explicit one such as ftp://, or a host\n name and port with no scheme, such as localhost:8080, which reads as the\n scheme localhost:. Put https:// or http:// in front.\nThe Perplexity base URL is not a valid absolute URL β€” the value does not\n parse as a URL at all: a bare host name such as api.perplexity.ai (the likely\n mistake), an IP address and port such as 127.0.0.1:8080, a path, or a scheme\n with no host. Write the origin with its scheme.\nA refused base URL in the debug log β€” it is not there. A base URL that\n NeuroLink refuses (credentials, a query string, a fragment, a scheme other than\n http or https, or not a URL at all) is never written to the debug log: the line\n shows (invalid) in its place, because such a value can carry a secret.\nImage N is not a PNG, JPEG or WebP image β€” Perplexity reads only those\n three. Convert the image first.\nImage N is … pixels; Perplexity reads at most 2048 tiles β€” resize the\n image to fit, for example 1440 Γ— 1440 or 2048 Γ— 1024.\nA request with an image stalls until it times out, or fails as server with\n HTTP 504 when the timeout is longer than a minute β€” an image over the tile\n cap does this. NeuroLink refuses those before","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"Troubleshooting","lvl3":""}},
6895
6896
  {"objectID":"6d580e7ffb3867905a72879cdccbab76b5df280677e9d18b0029fd5bc5092025","title":"See also","url":"/docs/getting-started/providers/perplexity-decider#see-also","content":"The decide inference type\nTypeSafe (Jev) Provider Guide\nLaya Provider Guide\nXOR Provider Guide\nPerplexity text provider\nPerplexity Decisions API reference","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Decisions Provider Guide","lvl2":"See also","lvl3":""}},
6896
6897
  {"objectID":"6d55ee7ec0f21369a70b421eaeaddf6b44fe88746beb28c252588d42d97048b7","title":"Perplexity Provider Guide","url":"/docs/getting-started/providers/perplexity","content":"Perplexity Provider Guide\n\nWeb-search-augmented generation via Perplexity's Sonar models\n\nOverview\n\nPerplexity hosts a family of LLMs (Sonar,\nSonar Pro, Sonar Reasoning) that pair the model with a live web search\nbackend; responses include citations to the documents the model relied on.\n\nKey Facts\nProtocol: OpenAI-compatible (/chat/completions)\nDefault base URL: https://api.perplexity.ai\nDefault model: sonar\nCitations: Returned via citations field on the response\nStreaming: Yes\nTool calling: No\n\nQuick Start\nGet an API Key\n\nhttps://www.perplexity.ai/settings/api\nConfigure\n\nPERPLEXITY_API_KEY also configures decisions. The same variable configures\nthe Perplexity Decisions provider (perplexity-decider,\nwhich serves decide()). So setting it for Sonar also lets NeuroLink's built-in\nfeatures send decision requests to Perplexity when no TypeSafe, Laya or XOR\nprovider is configured, and context compaction needs no other opt-in to do so.\nTo avoid that, pass the key through the SDK as credentials.perplexity.apiKey\ninstead of the environment, and keep it out of .env too: the SDK and the CLI\nload that file into the environment, so a PERPLEXITY_API_KEY line like the one\nabove would still configure decisions. (That the text provider reads this slice\nis taken from the code and has not been run against the live API.) See\nWhat is sent to Perplexity\nand One key, two providers.\nGenerate\n\nSupported Models\n\n| Model ID | Notes |\n| ----------------- | ----------------------------------- |\n| sonar | Default; fast search-augmented chat |\n| sonar-pro | Larger context, deeper search |\n| sonar-reasoning | Chain-of-thought reasoning |\n\nCLI Usage\n\nProvider Aliases\n\n| Alias | Example |\n| ------------ | ----------------------- |\n| perplexity | --provider perplexity |\n\nConfiguration Reference\n\n| Environment Variable | Required | Default |\n| --------------------- | -------- | --------------------------- |\n| PERPLEXITY_API_KEY | Yes | β€” |\n| PERPLEXITY_MODEL | No | sonar |\n| PERPLEXITY_BASE_URL | No | https://api.perplexity.ai |\n\nFeature Support Matrix\n\n| Feature | Support |\n| ----------------- | ------------ |\n| Text generation | Yes |\n| Streaming | Yes |\n| Tool calling | No |\n| Structured output | Limited |\n| Web search | Yes (native) |\n| Citations | Yes |\n\nSee Also\nPerplexity Decisions Provider β€” typed, calibrated decide() judgments on the same key\nAnthropic Provider β€” web-search via the web_search tool\nVertex Provider β€” Google search grounding","hierarchy":{"lvl0":"Getting Started","lvl1":"Perplexity Provider Guide","lvl2":"","lvl3":""}},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "12.44.4",
3
+ "version": "12.44.6",
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": {
@@ -286,7 +286,8 @@
286
286
  "test:native-failure-events": "pnpm exec tsx test/continuous-test-suite-native-failure-events.ts",
287
287
  "test:native-audio-model-aware": "pnpm exec tsx test/continuous-test-suite-native-audio-model-aware.ts",
288
288
  "test:cli-json-output": "pnpm exec tsx test/continuous-test-suite-cli-json-output.ts",
289
- "test:logging-guidelines": "pnpm exec tsx test/continuous-test-suite-logging-guidelines.ts"
289
+ "test:logging-guidelines": "pnpm exec tsx test/continuous-test-suite-logging-guidelines.ts",
290
+ "test:proxy-polyfills": "pnpm exec tsx test/continuous-test-suite-proxy-polyfills.ts"
290
291
  },
291
292
  "files": [
292
293
  "dist",
@@ -444,6 +445,7 @@
444
445
  "chardet": "2.1.1",
445
446
  "croner": "^9.1.0",
446
447
  "csv-parser": "^3.2.0",
448
+ "diff": "^9.0.0",
447
449
  "dotenv": "^17.3.1",
448
450
  "eventsource-parser": "^3.0.8",
449
451
  "fast-xml-parser": "^5.7.0",
@@ -565,7 +567,6 @@
565
567
  "@vercel/ncc": "^0.38.4",
566
568
  "concurrently": "^9.2.1",
567
569
  "conventional-changelog-conventionalcommits": "^9.1.0",
568
- "diff": "^9.0.0",
569
570
  "esbuild": "^0.28.1",
570
571
  "eslint": "^10.0.2",
571
572
  "glob": "^13.0.6",