@juspay/neurolink 12.47.14 → 12.48.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/dist/auth/middleware/AuthMiddleware.d.ts +1 -1
  3. package/dist/browser/neurolink.min.js +578 -565
  4. package/dist/cli/factories/commandFactory.d.ts +7 -0
  5. package/dist/cli/factories/commandFactory.js +26 -0
  6. package/dist/cli/loop/optionsSchema.js +9 -0
  7. package/dist/context/budgetChecker.js +54 -2
  8. package/dist/context/contextDecision.js +2 -0
  9. package/dist/context/toolPairRepair.d.ts +12 -0
  10. package/dist/context/toolPairRepair.js +29 -3
  11. package/dist/core/baseProvider.d.ts +92 -3
  12. package/dist/core/baseProvider.js +254 -10
  13. package/dist/core/conversationMemoryManager.js +17 -2
  14. package/dist/core/loopEngine.js +1 -1
  15. package/dist/core/modules/MessageBuilder.js +11 -3
  16. package/dist/core/modules/TelemetryHandler.d.ts +2 -2
  17. package/dist/core/modules/ToolsManager.d.ts +35 -0
  18. package/dist/core/modules/ToolsManager.js +159 -55
  19. package/dist/core/nativeGenerateLoop.d.ts +58 -1
  20. package/dist/core/nativeGenerateLoop.js +277 -3
  21. package/dist/core/redisConversationMemoryManager.js +10 -3
  22. package/dist/core/resolveRequestKind.d.ts +24 -4
  23. package/dist/core/resolveRequestKind.js +31 -4
  24. package/dist/core/toolExecutionRecorder.d.ts +6 -0
  25. package/dist/core/toolExecutionRecorder.js +24 -2
  26. package/dist/core/toolRoutingDecision.js +1 -0
  27. package/dist/factories/mediaHandlerCatalog.js +5 -0
  28. package/dist/factories/providerDescriptors.js +15 -0
  29. package/dist/files/fileTools.d.ts +1 -1
  30. package/dist/index.d.ts +5 -2
  31. package/dist/index.js +9 -2
  32. package/dist/memory/condensationPrompt.d.ts +8 -0
  33. package/dist/memory/condensationPrompt.js +29 -0
  34. package/dist/memory/hippocampusInitializer.d.ts +14 -2
  35. package/dist/memory/hippocampusInitializer.js +64 -3
  36. package/dist/neurolink.d.ts +252 -3
  37. package/dist/neurolink.js +898 -43
  38. package/dist/providers/amazonBedrock/client.js +6 -0
  39. package/dist/providers/amazonSagemaker.js +14 -1
  40. package/dist/providers/anthropic/client.js +148 -19
  41. package/dist/providers/anthropic/loopAdapter.js +2 -2
  42. package/dist/providers/googleAiStudio/client.js +2 -1
  43. package/dist/providers/openaiChatCompletionsBase.js +103 -23
  44. package/dist/providers/systemOneDecision.d.ts +6 -0
  45. package/dist/providers/systemOneDecision.js +14 -63
  46. package/dist/providers/typesafe.d.ts +6 -0
  47. package/dist/providers/typesafe.js +6 -0
  48. package/dist/rag/retrieval/searchDecision.js +1 -0
  49. package/dist/routing/classifierRouter.js +6 -5
  50. package/dist/routing/classifierStrategies.js +8 -1
  51. package/dist/types/classifierRouter.d.ts +16 -3
  52. package/dist/types/common.d.ts +2 -0
  53. package/dist/types/config.d.ts +9 -0
  54. package/dist/types/context.d.ts +8 -1
  55. package/dist/types/conversation.d.ts +87 -0
  56. package/dist/types/decision.d.ts +210 -1
  57. package/dist/types/decision.js +9 -1
  58. package/dist/types/dispatch.d.ts +11 -4
  59. package/dist/types/generate.d.ts +118 -54
  60. package/dist/types/loopEngine.d.ts +7 -2
  61. package/dist/types/memory.d.ts +177 -9
  62. package/dist/types/openaiCompatible.d.ts +11 -3
  63. package/dist/types/stream.d.ts +13 -16
  64. package/dist/types/stt.d.ts +58 -1
  65. package/dist/types/tools.d.ts +14 -0
  66. package/dist/types/tools.js +8 -0
  67. package/dist/types/tts.d.ts +108 -0
  68. package/dist/types/voice.d.ts +41 -4
  69. package/dist/utils/decisionAnswers.d.ts +31 -1
  70. package/dist/utils/decisionAnswers.js +114 -0
  71. package/dist/utils/decisionLimits.d.ts +39 -0
  72. package/dist/utils/decisionLimits.js +116 -0
  73. package/dist/utils/logger.d.ts +7 -0
  74. package/dist/utils/logger.js +9 -0
  75. package/dist/utils/messageBuilder.d.ts +45 -1
  76. package/dist/utils/messageBuilder.js +393 -16
  77. package/dist/utils/multimodalOptionsBuilder.d.ts +1 -0
  78. package/dist/utils/multimodalOptionsBuilder.js +1 -0
  79. package/dist/utils/speechText.d.ts +41 -0
  80. package/dist/utils/speechText.js +364 -0
  81. package/dist/utils/toolResultStatus.d.ts +26 -0
  82. package/dist/utils/toolResultStatus.js +73 -0
  83. package/dist/utils/ttsProcessor.d.ts +29 -0
  84. package/dist/utils/ttsProcessor.js +84 -2
  85. package/dist/voice/index.d.ts +1 -0
  86. package/dist/voice/index.js +3 -0
  87. package/dist/voice/providers/ElevenLabsSTT.d.ts +42 -0
  88. package/dist/voice/providers/ElevenLabsSTT.js +351 -0
  89. package/dist/voice/providers/ElevenLabsTTS.d.ts +81 -1
  90. package/dist/voice/providers/ElevenLabsTTS.js +415 -74
  91. package/docs-site/static/search-index.json +48 -33
  92. package/package.json +5 -2
  93. package/dist/utils/toolEndEmitter.d.ts +0 -25
  94. package/dist/utils/toolEndEmitter.js +0 -64
@@ -2494,11 +2494,11 @@
2494
2494
  {"objectID":"a6a33dbdaa9f09d86a62e1a043a4583f57c1ced7b2e786830b73ed431d5faa15","title":"Or run all tests","url":"/docs/examples/mcp-tool-blocking-example#or-run-all-tests","content":"pnpm test\n`","hierarchy":{"lvl0":"Examples","lvl1":"Tool Blocking Feature Example","lvl2":"Or run all tests","lvl3":""}},
2495
2495
  {"objectID":"4063c82ce53cbddddb37aaa3f2c4e6cda3979f7c42245ab87dd1f9b32d952ebf","title":"Notes","url":"/docs/examples/mcp-tool-blocking-example#notes","content":"Blocked tools are filtered during discovery, so they won't appear in the list of available tools\nAttempts to execute blocked tools will throw an error with a clear message\nThe blockedTools array can be empty or omitted if no tools need to be blocked\nTool names are case-sensitive and must match exactly","hierarchy":{"lvl0":"Examples","lvl1":"Tool Blocking Feature Example","lvl2":"Notes","lvl3":""}},
2496
2496
  {"objectID":"5341e63ac43674fa9af2ce7263aeda1cd91585d86e51d5d3a89b1f372e615a1c","title":"Use Cases","url":"/docs/examples/use-cases","content":"This page has moved to Real-World Use Cases.","hierarchy":{"lvl0":"Examples","lvl1":"Use Cases","lvl2":"","lvl3":""}},
2497
- {"objectID":"663b4543baa0f126dd73ee25ad1e8111b108f06eec1f22e84f8cc195c99b00e8","title":"Audio Input & Transcription Guide","url":"/docs/features/audio-input","content":"Audio Input & Voice Conversations Guide\n\nNeuroLink provides comprehensive audio input capabilities, enabling real-time voice conversations with AI models. This guide covers currently available features, audio specifications, and upcoming enhancements.\n\nOverview\n\nCurrently Available\n\nNeuroLink supports the following audio capabilities today:\nReal-time voice conversations via Gemini Live (Google AI Studio)\nText-to-Speech (TTS) output via Google Cloud TTS, OpenAI TTS, ElevenLabs, and Azure TTS\nSpeech-to-Text (STT) via generate() and stream() options (Whisper/OpenAI STT, Google STT, Deepgram, Azure STT)\nWebSocket-based voice streaming for web applications\nBidirectional audio - speak and hear AI responses in real-time\n\nPlanned\n\nThe following features are planned for future releases:\nCLI commands: neurolink audio transcribe, neurolink audio analyze, neurolink audio summarize\nCLI commands: neurolink voice chat, neurolink voice demo\nCross-provider audio support (Anthropic, AWS Transcribe still planned)\nFile-based audio input processing\n\nProvider Support Matrix\n\n| Provider | Real-time Voice | TTS Output | Audio Transcription | Status |\n| -------------------- | --------------- | ---------- | ---------------------------- | ---------------- |\n| Google AI Studio | Yes | Yes | Yes (via Google STT) | Production Ready |\n| Google Vertex AI | Planned | Yes | Yes (via Google STT) | Available |\n| OpenAI | Planned | Yes | Yes (via Whisper/OpenAI STT) | Available |\n| Deepgram | Planned | No | Yes | Available |\n| Azure | Planned | Yes | Yes (via Azure STT) | Available |\n| Anthropic | Planned | Planned | Planned | Planned |\n| AWS Bedrock | Planned | Planned | Planned | Planned |\n\nSupported Model for Real-time Voice:\n\n| Model | Provider | Capabilities |\n| ---------------------------------------------- | --------- | -------------------------------- |\n| gemini-2.5-flash-preview-native-audio-dialog | Google AI | Bidirectional audio, low latency |\n\nQuick Start: Real-Time Voice (SDK)\n\nReal-time voice conversations are available through the SDK using Gemini Live's native audio dialog model.\n\nPrerequisites\n\nBasic Real-time Voice Streaming\n\nComplete Voice Session Example\n\nQuick Start: TTS Integration\n\nNeuroLink provides Text-to-Speech output via Google Cloud TTS. TTS can be combined with any text generation.\n\nCLI Usage\n\nSDK Usage\n\nFor comprehensive TTS documentation, see the TTS Integration Guide.\n\nVoice Demo Example\n\nNeuroLink includes a complete voice demo application demonstrating real-time bidirectional audio conversations.\n\nLocation\n\nRunning the Demo\n\nThe demo will:\nStart a WebSocket server on port 5175 (or next available port)\nOpen your browser automatically to the demo interface\nAllow you to speak and receive real-time AI audio responses\n\nDemo Architecture\n\nKey Code from Voice Demo Server\n\nAudio Specifications\n\nInput Audio Format\n\n| Parameter | Value | Notes |\n| --------------- | ------------------- | ------------------------------------ |\n| Encoding | PCM16LE | 16-bit signed integer, little-endian |\n| Sample Rate | 16,000 Hz | 16 kHz mono |\n| Channels | 1 (mono) | Stereo not supported in Phase 1 |\n| Frame Size | 20-60ms recommended | ~320-960 samples per frame |\n| Byte Order | Little-endian | Intel/ARM standard |\n\nOutput Audio Format\n\n| Parameter | Value | Notes |\n| --------------- | ------------- | ------------------------------------ |\n| Encoding | PCM16LE | 16-bit signed integer, little-endian |\n| Sample Rate | 24,000 Hz | 24 kHz mono |\n| Channels | 1 (mono) | Single channel output |\n| Byte Order | Little-endian | Intel/ARM standard |\n\nConverting Audio Formats\n\nFrom Float32 to PCM16LE (for input):\n\nFrom PCM16LE to Float32 (for output playback):\n\nBrowser Audio Context Setup\n\nSDK API Reference\n\nAudioInputSpec\n\nConfiguration for streaming audio input.\n\nAudioChunk\n\nAudio output chunk received from streaming responses.\n\nStreamOptions with Audio\n\nStream Result Events\n\nAudioContent (File-based - Future)\n\nFor file-based audio input (planned feature).\n\nRoadmap\n\nPhase 1 (Current)\nReal-time voice with Gemini Live\nBidirectional audio streaming via SDK\nVoice demo example application\nTTS output integration\n\nPhase 2 (Planned)\nCLI Voice Commands\nAudio Transcription\n\n \n\nPhase 3 (Partially Available)\nSpeech-to-Text via generate() / stream() — Available now via the stt option. There is no standalone neur","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"","lvl3":""}},
2497
+ {"objectID":"663b4543baa0f126dd73ee25ad1e8111b108f06eec1f22e84f8cc195c99b00e8","title":"Audio Input & Transcription Guide","url":"/docs/features/audio-input","content":"Audio Input & Voice Conversations Guide\n\nNeuroLink provides comprehensive audio input capabilities, enabling real-time voice conversations with AI models. This guide covers currently available features, audio specifications, and upcoming enhancements.\n\nOverview\n\nCurrently Available\n\nNeuroLink supports the following audio capabilities today:\nReal-time voice conversations via Gemini Live (Google AI Studio)\nText-to-Speech (TTS) output via Google Cloud TTS, OpenAI TTS, ElevenLabs, and Azure TTS\nSpeech-to-Text (STT) via generate() and stream() options (Whisper/OpenAI STT, Google STT, Deepgram, Azure STT, ElevenLabs Scribe)\nWebSocket-based voice streaming for web applications\nBidirectional audio - speak and hear AI responses in real-time\n\nPlanned\n\nThe following features are planned for future releases:\nCLI commands: neurolink audio transcribe, neurolink audio analyze, neurolink audio summarize\nCLI commands: neurolink voice chat, neurolink voice demo\nCross-provider audio support (Anthropic, AWS Transcribe still planned)\nFile-based audio input processing\n\nProvider Support Matrix\n\n| Provider | Real-time Voice | TTS Output | Audio Transcription | Status |\n| -------------------- | --------------- | ---------- | ---------------------------------- | ---------------- |\n| Google AI Studio | Yes | Yes | Yes (via Google STT) | Production Ready |\n| Google Vertex AI | Planned | Yes | Yes (via Google STT) | Available |\n| OpenAI | Planned | Yes | Yes (via Whisper/OpenAI STT) | Available |\n| Deepgram | Planned | No | Yes | Available |\n| ElevenLabs | Planned | Yes | Yes (via Scribe, elevenlabs-stt) | Available |\n| Azure | Planned | Yes | Yes (via Azure STT) | Available |\n| Anthropic | Planned | Planned | Planned | Planned |\n| AWS Bedrock | Planned | Planned | Planned | Planned |\n\nSupported Model for Real-time Voice:\n\n| Model | Provider | Capabilities |\n| ---------------------------------------------- | --------- | -------------------------------- |\n| gemini-2.5-flash-preview-native-audio-dialog | Google AI | Bidirectional audio, low latency |\n\nQuick Start: Real-Time Voice (SDK)\n\nReal-time voice conversations are available through the SDK using Gemini Live's native audio dialog model.\n\nPrerequisites\n\nBasic Real-time Voice Streaming\n\nComplete Voice Session Example\n\nQuick Start: TTS Integration\n\nNeuroLink provides Text-to-Speech output via Google Cloud TTS. TTS can be combined with any text generation.\n\nCLI Usage\n\nSDK Usage\n\nFor comprehensive TTS documentation, see the TTS Integration Guide.\n\nVoice Demo Example\n\nNeuroLink includes a complete voice demo application demonstrating real-time bidirectional audio conversations.\n\nLocation\n\nRunning the Demo\n\nThe demo will:\nStart a WebSocket server on port 5175 (or next available port)\nOpen your browser automatically to the demo interface\nAllow you to speak and receive real-time AI audio responses\n\nDemo Architecture\n\nKey Code from Voice Demo Server\n\nAudio Specifications\n\nInput Audio Format\n\n| Parameter | Value | Notes |\n| --------------- | ------------------- | ------------------------------------ |\n| Encoding | PCM16LE | 16-bit signed integer, little-endian |\n| Sample Rate | 16,000 Hz | 16 kHz mono |\n| Channels | 1 (mono) | Stereo not supported in Phase 1 |\n| Frame Size | 20-60ms recommended | ~320-960 samples per frame |\n| Byte Order | Little-endian | Intel/ARM standard |\n\nOutput Audio Format\n\n| Parameter | Value | Notes |\n| --------------- | ------------- | ------------------------------------ |\n| Encoding | PCM16LE | 16-bit signed integer, little-endian |\n| Sample Rate | 24,000 Hz | 24 kHz mono |\n| Channels | 1 (mono) | Single channel output |\n| Byte Order | Little-endian | Intel/ARM standard |\n\nConverting Audio Formats\n\nFrom Float32 to PCM16LE (for input):\n\nFrom PCM16LE to Float32 (for output playback):\n\nBrowser Audio Context Setup\n\nSDK API Reference\n\nAudioInputSpec\n\nConfiguration for streaming audio input.\n\nAudioChunk\n\nAudio output chunk received from streaming responses.\n\nStreamOptions with Audio\n\nStream Result Events\n\nAudioContent (File-based - Future)\n\nFor file-based audio input (planned feature).\n\nRoadmap\n\nPhase 1 (Current)\nReal-time voice with Gemini Live\nBidirectional audio streaming via SDK\nVoice demo example application\nTTS output integration\n\nPhase 2 (Planned)","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"","lvl3":""}},
2498
2498
  {"objectID":"a32f77567943264cd3a10e47531543e59494110d83eacb73e06c777b325a954d","title":"Audio Input & Voice Conversations Guide","url":"/docs/features/audio-input#audio-input-voice-conversations-guide","content":"NeuroLink provides comprehensive audio input capabilities, enabling real-time voice conversations with AI models. This guide covers currently available features, audio specifications, and upcoming enhancements.","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Audio Input & Voice Conversations Guide","lvl3":""}},
2499
- {"objectID":"e6130b0676f57a7cf79b67937961a503147a86874d2071c61df0cd0c5983606b","title":"Currently Available","url":"/docs/features/audio-input#currently-available","content":"NeuroLink supports the following audio capabilities today:\nReal-time voice conversations via Gemini Live (Google AI Studio)\nText-to-Speech (TTS) output via Google Cloud TTS, OpenAI TTS, ElevenLabs, and Azure TTS\nSpeech-to-Text (STT) via generate() and stream() options (Whisper/OpenAI STT, Google STT, Deepgram, Azure STT)\nWebSocket-based voice streaming for web applications\nBidirectional audio - speak and hear AI responses in real-time","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Currently Available","lvl3":""}},
2499
+ {"objectID":"e6130b0676f57a7cf79b67937961a503147a86874d2071c61df0cd0c5983606b","title":"Currently Available","url":"/docs/features/audio-input#currently-available","content":"NeuroLink supports the following audio capabilities today:\nReal-time voice conversations via Gemini Live (Google AI Studio)\nText-to-Speech (TTS) output via Google Cloud TTS, OpenAI TTS, ElevenLabs, and Azure TTS\nSpeech-to-Text (STT) via generate() and stream() options (Whisper/OpenAI STT, Google STT, Deepgram, Azure STT, ElevenLabs Scribe)\nWebSocket-based voice streaming for web applications\nBidirectional audio - speak and hear AI responses in real-time","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Currently Available","lvl3":""}},
2500
2500
  {"objectID":"a323022725e083a1bd3cc081f0bb30671115674fd3059d81a59a1e5748bf2e40","title":"Planned","url":"/docs/features/audio-input#planned","content":"The following features are planned for future releases:\nCLI commands: neurolink audio transcribe, neurolink audio analyze, neurolink audio summarize\nCLI commands: neurolink voice chat, neurolink voice demo\nCross-provider audio support (Anthropic, AWS Transcribe still planned)\nFile-based audio input processing","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Planned","lvl3":""}},
2501
- {"objectID":"8d491157b4f86d94b665dc67602d242028afbb11311c376e92d5fb72180b9dd2","title":"Provider Support Matrix","url":"/docs/features/audio-input#provider-support-matrix","content":"| Provider | Real-time Voice | TTS Output | Audio Transcription | Status |\n| -------------------- | --------------- | ---------- | ---------------------------- | ---------------- |\n| Google AI Studio | Yes | Yes | Yes (via Google STT) | Production Ready |\n| Google Vertex AI | Planned | Yes | Yes (via Google STT) | Available |\n| OpenAI | Planned | Yes | Yes (via Whisper/OpenAI STT) | Available |\n| Deepgram | Planned | No | Yes | Available |\n| Azure | Planned | Yes | Yes (via Azure STT) | Available |\n| Anthropic | Planned | Planned | Planned | Planned |\n| AWS Bedrock | Planned | Planned | Planned | Planned |\n\nSupported Model for Real-time Voice:\n\n| Model | Provider | Capabilities |\n| ---------------------------------------------- | --------- | -------------------------------- |\n| gemini-2.5-flash-preview-native-audio-dialog | Google AI | Bidirectional audio, low latency |","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Provider Support Matrix","lvl3":""}},
2501
+ {"objectID":"8d491157b4f86d94b665dc67602d242028afbb11311c376e92d5fb72180b9dd2","title":"Provider Support Matrix","url":"/docs/features/audio-input#provider-support-matrix","content":"| Provider | Real-time Voice | TTS Output | Audio Transcription | Status |\n| -------------------- | --------------- | ---------- | ---------------------------------- | ---------------- |\n| Google AI Studio | Yes | Yes | Yes (via Google STT) | Production Ready |\n| Google Vertex AI | Planned | Yes | Yes (via Google STT) | Available |\n| OpenAI | Planned | Yes | Yes (via Whisper/OpenAI STT) | Available |\n| Deepgram | Planned | No | Yes | Available |\n| ElevenLabs | Planned | Yes | Yes (via Scribe, elevenlabs-stt) | Available |\n| Azure | Planned | Yes | Yes (via Azure STT) | Available |\n| Anthropic | Planned | Planned | Planned | Planned |\n| AWS Bedrock | Planned | Planned | Planned | Planned |\n\nSupported Model for Real-time Voice:\n\n| Model | Provider | Capabilities |\n| ---------------------------------------------- | --------- | -------------------------------- |\n| gemini-2.5-flash-preview-native-audio-dialog | Google AI | Bidirectional audio, low latency |","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Provider Support Matrix","lvl3":""}},
2502
2502
  {"objectID":"675ff9de750e2e6e6eabfd9b19d8e2107d5c403305242ddd9e306f98b799635e","title":"Quick Start: Real-Time Voice (SDK)","url":"/docs/features/audio-input#quick-start-real-time-voice-sdk","content":"Real-time voice conversations are available through the SDK using Gemini Live's native audio dialog model.","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Quick Start: Real-Time Voice (SDK)","lvl3":""}},
2503
2503
  {"objectID":"19f0a0ab6d49a5c80fc761412dcedc3e85257f38aed0542bd0561f58d95febdf","title":"Prerequisites","url":"/docs/features/audio-input#prerequisites","content":"`bash","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Prerequisites","lvl3":""}},
2504
2504
  {"objectID":"73a73af8929aec5bebdfa114ba2a35ba5f7d8b0c78bfbdd21131132020de7368","title":"OR","url":"/docs/features/audio-input#or","content":"`","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"OR","lvl3":""}},
@@ -2522,7 +2522,7 @@
2522
2522
  {"objectID":"64814f99af3a8c638dc56306ba5fc44bb6e5b272f8d938ab34259be39af63e4e","title":"AudioContent (File-based - Future)","url":"/docs/features/audio-input#audiocontent-file-based---future","content":"For file-based audio input (planned feature).","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"AudioContent (File-based - Future)","lvl3":""}},
2523
2523
  {"objectID":"fe70dce325b6ac96a408645173cdd649cc0abc95d6d9db868e0e4c4446c75435","title":"Phase 1 (Current)","url":"/docs/features/audio-input#phase-1-current","content":"Real-time voice with Gemini Live\nBidirectional audio streaming via SDK\nVoice demo example application\nTTS output integration","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Phase 1 (Current)","lvl3":""}},
2524
2524
  {"objectID":"ec029d3f48cdb5f19fbcd4e201f677de97cff852a4d01194570def1804083244","title":"Phase 2 (Planned)","url":"/docs/features/audio-input#phase-2-planned","content":"CLI Voice Commands\nAudio Transcription","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Phase 2 (Planned)","lvl3":""}},
2525
- {"objectID":"4052f7016112515e4c48c4c7369cea3135af4fa874d935ab0d0382a9c7ffef4f","title":"Phase 3 (Partially Available)","url":"/docs/features/audio-input#phase-3-partially-available","content":"Speech-to-Text via generate() / stream() — Available now via the stt option. There is no standalone neurolink.transcribe() method; STT is integrated directly into generate() and stream():\n\n \n\n CLI equivalent:\n\n \n\n Available STT providers: whisper / openai-stt, google-stt, deepgram, azure-stt\n\n CLI STT flags: --stt, --stt-provider <provider>, --input-audio <file>, --stt-language <lang>\nCross-provider Audio Support\nAnthropic voice capabilities — Planned\nAWS Transcribe — Planned\nFile-based Audio Input","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Phase 3 (Partially Available)","lvl3":""}},
2525
+ {"objectID":"4052f7016112515e4c48c4c7369cea3135af4fa874d935ab0d0382a9c7ffef4f","title":"Phase 3 (Partially Available)","url":"/docs/features/audio-input#phase-3-partially-available","content":"Speech-to-Text via generate() / stream() — Available now via the stt option. There is no standalone neurolink.transcribe() method; STT is integrated directly into generate() and stream():\n\n \n\n CLI equivalent:\n\n \n\n Available STT providers: whisper / openai-stt, google-stt, deepgram, azure-stt, elevenlabs-stt (aliases scribe, elevenlabs)\n\n CLI STT flags: --stt, --stt-provider <provider>, --input-audio <file>, --stt-language <lang>\nCross-provider Audio Support\nAnthropic voice capabilities — Planned\nAWS Transcribe — Planned\nFile-based Audio Input","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Phase 3 (Partially Available)","lvl3":""}},
2526
2526
  {"objectID":"c2f07309fbd4e1af66d45bb90451dd8c9f9f62b6fbda59435f2de302a7ba8451","title":"Required Environment Variables","url":"/docs/features/audio-input#required-environment-variables","content":"`bash","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Required Environment Variables","lvl3":""}},
2527
2527
  {"objectID":"8c38f46a58844c8f91aa4f8d748b70535368b4328ca702e5a17f2d34cd9b2848","title":"OR use the same GOOGLE_AI_API_KEY with Cloud TTS API enabled","url":"/docs/features/audio-input#or-use-the-same-google_ai_api_key-with-cloud-tts-api-enabled","content":"`","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"OR use the same GOOGLE_AI_API_KEY with Cloud TTS API enabled","lvl3":""}},
2528
2528
  {"objectID":"1cca651280e08979aa7530b5865c51a0cc7ca8d763740d7c3b113dade8207585","title":"API Key Configuration","url":"/docs/features/audio-input#api-key-configuration","content":"For Gemini Live and TTS to work with an API key:\nGo to Google Cloud Console > APIs & Services > Credentials\nCreate or select your API key\nUnder \"API restrictions\", enable:\nGenerative Language API (for Gemini)\nCloud Text-to-Speech API (for TTS output)","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"API Key Configuration","lvl3":""}},
@@ -2530,7 +2530,7 @@
2530
2530
  {"objectID":"3666c2d8d6b40a6c724ff2038fd852cac1d4499211f0070664568c2a43c58dbc","title":"Audio Quality Issues","url":"/docs/features/audio-input#audio-quality-issues","content":"Clipping/Distortion:\nEnsure input samples are normalized to [-1, 1] range\nCheck gain levels before PCM conversion\n\nEcho/Feedback:\nMute microphone during AI audio playback\nImplement voice activity detection (VAD)\n\nLatency:\nUse smaller frame sizes (20ms)\nProcess audio in real-time, avoid buffering\nUse WebSocket for low-latency transport","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Audio Quality Issues","lvl3":""}},
2531
2531
  {"objectID":"c4735ccd8979c95a1a8b2ee8ef9e09cffceb62ecf4e7dbc35e80df6260c67eaf","title":"Debug Mode","url":"/docs/features/audio-input#debug-mode","content":"Enable debug logging to troubleshoot audio issues:","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Debug Mode","lvl3":""}},
2532
2532
  {"objectID":"5dd242268990d7407d240c3e419eda43acc8e8f28d62f4fb9f6ae0302e337e98","title":"Related Features","url":"/docs/features/audio-input#related-features","content":"Audio & Voice:\nTTS Integration Guide - Complete Text-to-Speech documentation\nVideo Generation - AI-powered video with audio\nPPT Generation - AI-powered PowerPoint presentations\n\nMultimodal Capabilities:\nMultimodal Guide - Images, PDFs, CSV inputs\nPDF Support - Document processing\n\nAdvanced Features:\nStreaming - Stream AI responses in real-time\nProvider Orchestration - Multi-provider failover\n\nDocumentation:\nCLI Commands - Complete CLI reference\nSDK API Reference - Full API documentation\nTroubleshooting - Extended error catalog","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Related Features","lvl3":""}},
2533
- {"objectID":"da325dca7aa585f458336acc2e7671004db8097ef1b4babdabdf6c0dadab102d","title":"Summary","url":"/docs/features/audio-input#summary","content":"NeuroLink's audio input capabilities provide:\n\nCurrently Available:\nReal-time voice conversations via Gemini Live\nBidirectional audio streaming (speak and hear)\nTTS output via Google Cloud, OpenAI TTS, ElevenLabs, and Azure TTS\nSTT via generate({ stt: { ... } }) — Whisper/OpenAI STT, Google STT, Deepgram, Azure STT\nVoice demo example application\nPCM16LE audio format support\n\nPlanned:\nCLI voice commands (voice chat, audio transcribe)\nAnthropic and AWS Transcribe audio support\nFile-based audio processing\n\nNext Steps:\nSet up environment variables\nTry the voice demo application\nIntegrate real-time voice in your SDK code\nExplore TTS output for text-to-speech\nCheck troubleshooting if you encounter issues","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Summary","lvl3":""}},
2533
+ {"objectID":"da325dca7aa585f458336acc2e7671004db8097ef1b4babdabdf6c0dadab102d","title":"Summary","url":"/docs/features/audio-input#summary","content":"NeuroLink's audio input capabilities provide:\n\nCurrently Available:\nReal-time voice conversations via Gemini Live\nBidirectional audio streaming (speak and hear)\nTTS output via Google Cloud, OpenAI TTS, ElevenLabs, and Azure TTS\nSTT via generate({ stt: { ... } }) — Whisper/OpenAI STT, Google STT, Deepgram, Azure STT, ElevenLabs Scribe\nVoice demo example application\nPCM16LE audio format support\n\nPlanned:\nCLI voice commands (voice chat, audio transcribe)\nAnthropic and AWS Transcribe audio support\nFile-based audio processing\n\nNext Steps:\nSet up environment variables\nTry the voice demo application\nIntegrate real-time voice in your SDK code\nExplore TTS output for text-to-speech\nCheck troubleshooting if you encounter issues","hierarchy":{"lvl0":"Features","lvl1":"Audio Input & Transcription Guide","lvl2":"Summary","lvl3":""}},
2534
2534
  {"objectID":"ed053e7b833b8a623c856b423196d8d1dde3599d21b1976ce7a5fe867487cce3","title":"Authentication Providers","url":"/docs/features/authentication-providers","content":"Authentication Providers\n\nStatus: Stable | Availability: SDK + CLI + Server\n\nOverview\n\nNeuroLink ships with a pluggable authentication system that validates tokens, manages sessions, and enforces role-based access control (RBAC) across your AI endpoints. Rather than forcing a single auth solution, NeuroLink supports 11 providers through a unified interface so you can use the same identity platform your application already relies on.\n\nKey capabilities:\nToken validation -- verify JWTs and opaque tokens from any supported provider\nSession management -- in-memory or Redis-backed session storage with auto-refresh\nRBAC enforcement -- role and permission checks with hierarchical wildcard support\nPer-call authentication -- validate tokens on every generate() or stream() call\nMiddleware pipeline -- composable auth, RBAC, and rate-limiting middleware for server routes\nAsyncLocalStorage context -- access the authenticated user from anywhere in the request lifecycle without explicit parameter passing\nCLI management -- list providers, validate tokens, and check health from the command line\n\nQuick Start\n\nSDK -- Constructor Auth Config\n\nPass authentication configuration in the NeuroLink constructor. The provider is lazily initialized on first use.\n\nSDK -- Per-Call Token Validation\n\nWhen an auth provider is configured, pass auth: { token } to generate() or stream() to validate the caller's token before the AI request executes. Validated user identity is automatically injected into the request context.\n\nSDK -- Pre-Validated Request Context\n\nIf your server has already validated the user, pass requestContext instead. When both auth.token and requestContext are provided, token-derived identity fields take precedence to prevent privilege escalation.\n\nServer Middleware\n\nProtect HTTP routes with composable middleware.\n\nProvider Support\n\n| Provider | Type | JWT Validation | Session Mgmt | RBAC | Health Check | Aliases |\n| ----------- | ------------- | -------------- | ------------ | ---- | ------------ | --------------------------------- |\n| Auth0 | auth0 | Yes | Yes | Yes | Yes | auth0-jwt, auth0-oauth |\n| Clerk | clerk | Yes | Yes | Yes | Yes | clerk-jwt |\n| Firebase | firebase | Yes | Yes | Yes | Yes | firebase-auth |\n| Supabase | supabase | Yes | Yes | Yes | Yes | supabase-auth |\n| AWS Cognito | cognito | Yes | Yes | Yes | Yes | aws-cognito, amazon-cognito |\n| Keycloak | keycloak | Yes | Yes | Yes | Yes | keycloak-oidc |\n| WorkOS | workos | Yes | Yes | Yes | Yes | workos-sso, work-os |\n| Better Auth | better-auth | Yes | Yes | Yes | Yes | betterauth, better_auth |\n| OAuth2 | oauth2 | Yes | Yes | Yes | Yes | oauth, oidc, openid-connect |\n| JWT | jwt | Yes | Yes | Yes | Yes | jwt-auth, jwt-token |\n| Custom | custom | Yes | Yes | Yes | Yes | custom-auth |\n\nAll providers implement the AuthProvider interface, ensuring a consistent API regardless of which identity platform you choose.\n\nSDK API\n\nConstructor Configuration\n\nThe auth field in NeurolinkConstructorConfig accepts several forms:\n\nThe NeuroLinkAuthConfig union type supports all 11 provider types with their specific config shapes:\n\n| Config Type | Required Fields |\n| ------------------------------------- | ------------------------------------------ |\n| { type: \"auth0\"; config: ... } | domain, clientId |\n| { type: \"clerk\"; config: ... } | secretKey |\n| { type: \"firebase\"; config: ... } | projectId |\n| { type: \"supabase\"; config: ... } | url, anonKey |\n| { type: \"cognito\"; config: ... } | userPoolId, clientId, region |\n| { type: \"keycloak\"; config: ... } | serverUrl, realm, clientId |\n| { type: \"workos\"; config: ... } | apiKey, clientId |\n| { type: \"better-auth\"; config: ...} | secret, baseUrl |\n| { type: \"oauth2\"; config: ... } | clientId, authorizationUrl, tokenUrl |\n| { type: \"jwt\"; config: ... } | secret or publicKey |\n| { type: \"custom\"; config: ... } | validateToken function |\n\nsetAuthProvider(config)\n\nSet or change the authentication provider at runtime.\n\ngetAuthProvider()\n\nGet the currently configured authentication provider, or undefined if none is set.\n\nsetAuthContext(context)\n\nSet the current","hierarchy":{"lvl0":"Features","lvl1":"Authentication Providers","lvl2":"","lvl3":""}},
2535
2535
  {"objectID":"b8e1dc28b6d943c42b083e5a7fa691a81822cb83ed865eba567871bb2da0f7be","title":"Authentication Providers","url":"/docs/features/authentication-providers#authentication-providers","content":"Status: Stable | Availability: SDK + CLI + Server","hierarchy":{"lvl0":"Features","lvl1":"Authentication Providers","lvl2":"Authentication Providers","lvl3":""}},
2536
2536
  {"objectID":"176a251158462a4eef0a027e59d3cb1b6060317255bdd3c4fab77bd60c183f72","title":"Overview","url":"/docs/features/authentication-providers#overview","content":"NeuroLink ships with a pluggable authentication system that validates tokens, manages sessions, and enforces role-based access control (RBAC) across your AI endpoints. Rather than forcing a single auth solution, NeuroLink supports 11 providers through a unified interface so you can use the same identity platform your application already relies on.\n\nKey capabilities:\nToken validation -- verify JWTs and opaque tokens from any supported provider\nSession management -- in-memory or Redis-backed session storage with auto-refresh\nRBAC enforcement -- role and permission checks with hierarchical wildcard support\nPer-call authentication -- validate tokens on every generate() or stream() call\nMiddleware pipeline -- composable auth, RBAC, and rate-limiting middleware for server routes\nAsyncLocalStorage context -- access the authenticated user from anywhere in the request lifecycle without explicit parameter passing\nCLI management -- list providers, validate tokens, and check health from the command line","hierarchy":{"lvl0":"Features","lvl1":"Authentication Providers","lvl2":"Overview","lvl3":""}},
@@ -2623,8 +2623,8 @@
2623
2623
  {"objectID":"b0a5b78dc4cfcabcd52b58ea94936ee81e97b59b5907f058ccba74881a7aeacd","title":"Context-window filtering","url":"/docs/features/classifier-router-catalog#context-window-filtering","content":"Nothing in routing read maxContextTokens before this. Two independent checks\nnow do:\nrankCatalogue() filters candidates whose contextWindow is below the\n request's estimated input tokens, applied only when it would leave something\n behind (an empty result falls back to the unfiltered pool rather than\n routing nowhere).\nThe classifier's own pick is separately vetoed. Even when jev picks a\n model directly, fitsRequest() checks whether that specific model's window\n can hold the request. If it can't, the pick is dropped regardless of\n confidence — this is a hard provider error, not a degraded answer, because\n an oversized request against a real model puts that model into ModelPool's\n permanent (10-year) cooldown. A wrong guess here is not \"less accurate,\" it\n is unrecoverable for the life of the process.","hierarchy":{"lvl0":"Features","lvl1":"The model catalogue","lvl2":"Context-window filtering","lvl3":""}},
2624
2624
  {"objectID":"e34966644db91aef39b46ef5c2f2fa259e9c828895197c9b2260a07c6e640bce","title":"What this is bad at","url":"/docs/features/classifier-router-catalog#what-this-is-bad-at","content":"Registry quality is coarse, and the catalogue path never shows its own\n work. Auto-enriched quality is a 3-bucket scale (high/medium/low)\n before buildModelCatalog() turns it into 1/2/3; two \"high\" models\n cannot be separated on capability alone. Worse for this page's topic: because\n the catalogue always populates cost/quality, its rendered line never\n shows the registry's own price, speed bucket, or \"strong at …\" scores — only\n the terse capability N / relative cost N form. Declare tiers/quality\n on a hand-declared pool member for finer control over the number itself; there\n is no way to get the richer rendering for a catalogue-sourced model.\nA catalogue candidate's \"relative cost\" is real pricing wearing a relative\n label. buildModelCatalog() seeds it from inputCostPer1K + outputCostPer1K\n — a small decimal like 0.00074 — not a small integer a host would typically\n pick for a hand-declared cost. The number is still correct and still never\n rendered as currency, but it does not compare cleanly against a hand-declared\n member's cost: 1 in the same pool, since one is a real price and the other\n is an arbitrary scale.\nUnknown-to-the-registry models rank on relative numbers, not real prices.\n A model the registry doesn't know (self-hosted, brand-new) keeps whatever\n cost/quality the host declared, compared only against other declared\n values on the same relative scale — never rendered as a dollar figure it\n isn't.\nA wide catalogue is still one choice question, and the cap is hard, not\n smart, when it does bind. Every model adds tokens to that single question;\n maxModels is the safeguard, and a model past it would simply never be\n offered rather than offered with lower priority. Today this is theoretical —\n the registry is 64 models against a default cap of 120, so nothing is\n dropped — but the mechanism has no ranking behavior for the day a registry\n does exceed it.\nPermissive reachability means occasional dead candidates.","hierarchy":{"lvl0":"Features","lvl1":"The model catalogue","lvl2":"What this is bad at","lvl3":""}},
2625
2625
  {"objectID":"2d7354001109ce1051977450cf365d1f2a8e13b345ad206ee23b1f5466228454","title":"See also","url":"/docs/features/classifier-router-catalog#see-also","content":"Classifier Router\nModel routing with a decision model\nThe decide inference type","hierarchy":{"lvl0":"Features","lvl1":"The model catalogue","lvl2":"See also","lvl3":""}},
2626
- {"objectID":"57703ab4e28ce3ad7f4c83d5d3e43f1b1d5541cbb2ac1d6f10f7a057046f0e1b","title":"Model routing with a decision model","url":"/docs/features/classifier-router-jev-strategy","content":"Model routing with a decision model\n\nThe classifier router has a jev strategy: one\ndecision-model round trip answers difficulty,\nrequired capabilities, risk and the model pick simultaneously, with a\ncalibrated confidence on each. This page is the strategy's own mechanics —\nclassifier-router.md covers the router as a whole.\n\nThe degradation contract. With no decision provider configured,\nresolveStrategy() resolves auto to heuristic, exactly as it always did.\nclassifyJev() itself never throws: any failure, timeout, or malformed answer\nfalls back to classifyHeuristic(). Configuring a decision provider (for example TYPESAFE_API_KEY or\nAI_GATEWAY_API_KEY) upgrades routing; it cannot make routing worse than before\nthe key existed. The same holds for PERPLEXITY_API_KEY, which is also the\nPerplexity text provider's key, and for CLOUDFLARE_API_KEY with\nCLOUDFLARE_ACCOUNT_ID, which are also the Cloudflare Workers AI text provider's\ntoken and account id.\n\nWhat goes into the state\n\nclassifyJev() sends the request truncated to 8000 characters, plus four\nsignals the caller already has on hand:\n\nAlongside it, one batch asks: difficulty (a choice over the five tiers),\nneeds_vision / needs_tools / needs_reasoning (boolean), risky\n(boolean), context (a score — see\nper-request context budget), and, only when the\npool has more than one member, model (a choice over the pool, rendered by\nthe catalogue). All of this rides in\none request. On TypeSafe that takes ~400ms, because latency is flat in question\ncount; on Perplexity each further question adds about 65 ms, up to 128 (see\nits guide); on\nCloudflare Clef a small request took 0.3 to 1.0 s on 2026-10-03 (see\nits guide). See\nthe batching rule.\n\nThe Cloudflare Clef endpoint ignores state text past about 2,048 tokens, and\nNeuroLink refuses a state it estimates at more than 1,500 tokens with\nmax_tokens_exceeded. A long request is therefore refused there, and the\nheuristic classifier's tier stands, as it does on any failure.\n\nThe difficulty rubric\n\nFive tiers, ordered easiest to hardest, worded about the shape of the work —\nthe model is never told a provider or model name:\n\n| Tier | Criterion |\n| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |\n| trivial | Mechanical and local: rename a symbol, fix a typo, add an import, run one named command, or answer something already stated. |\n| simple | A small localised change or a direct factual answer. One file, one obvious approach. |\n| moderate | Ordinary engineering: implement a well-specified change across a few files, write tests, fix a clearly described bug, review a small diff. |\n| hard | Deep reasoning: architecture and design, debugging a failure whose cause is unknown, security analysis, concurrency, cross-system refactors. |\n| expert | Frontier-level work: ambiguous requirements, novel design with no established pattern, or analysis where a wrong answer is costly and hard to detect. |\n\nAsymmetric confidence bars, and why they differ\n\nA verdict harder than the neutral tier (moderate) spends more if wrong; a\nverdict easier than neutral spends less if wrong. Those are not the same\nmistake:\nRouting a simple task to an expensive model wastes money. Cheap to be wrong\n about, so the bar to route up is low: minUpgradeConfidence defaults to\n 0.3.\nRouting a hard task to a weak model produces a wrong answer. Expensive to be\n wrong about, so the bar to route down is high: minDowngradeConfidence\n defaults to 0.6.\n\nBelow the applicable bar, the difficulty verdict is discarded and the heuristic\nclassifier's tier stands instead — not a downgraded jev answer, the ordinary\nzero-cost fallback.\n\nOne case skips both bars: a risky reading above 0.7 forces the tier to at\nleast hard, unconditionally. Risk can only ever raise the tier, never lower\none, and it is not itself gated by confidence.\n\nAsk about the act, not the subject\n\nThe risk question is not \"does this touch production, money, or credentials\":\n\nCarrying out this request would itself change production, move real money,\nexpose credentials, or alter data that cannot be restored. Writing or testing\ncode that deals with such things, without running it against the real system,\ndoes not count.\n\nThe naive phrasing was tried first and scored high on ordinary code that merely\nconcerns those things — \"add a refund endpoint that calls Stripe\" — which\nwould have escalated every such request to the most expensive tier. The second\nsentence is what separates writing the code from running it against something\nreal.\n\nThe model pick faces a bar too — but a different one\n\nWhen the pool has more than one member, jev is also asked to ch","hierarchy":{"lvl0":"Features","lvl1":"Model routing with a decision model","lvl2":"","lvl3":""}},
2627
- {"objectID":"bd360e5abf4e93403d1fb23a27c946fed1b86d8d8863a98519338332ca726639","title":"Model routing with a decision model","url":"/docs/features/classifier-router-jev-strategy#model-routing-with-a-decision-model","content":"The classifier router has a jev strategy: one\ndecision-model round trip answers difficulty,\nrequired capabilities, risk and the model pick simultaneously, with a\ncalibrated confidence on each. This page is the strategy's own mechanics —\nclassifier-router.md covers the router as a whole.\n\nThe degradation contract. With no decision provider configured,\nresolveStrategy() resolves auto to heuristic, exactly as it always did.\nclassifyJev() itself never throws: any failure, timeout, or malformed answer\nfalls back to classifyHeuristic(). Configuring a decision provider (for example TYPESAFE_API_KEY or\nAI_GATEWAY_API_KEY) upgrades routing; it cannot make routing worse than before\nthe key existed. The same holds for PERPLEXITY_API_KEY, which is also the\nPerplexity text provider's key, and for CLOUDFLARE_API_KEY with\nCLOUDFLARE_ACCOUNT_ID, which are also the Cloudflare Workers AI text provider's\ntoken and account id.","hierarchy":{"lvl0":"Features","lvl1":"Model routing with a decision model","lvl2":"Model routing with a decision model","lvl3":""}},
2626
+ {"objectID":"57703ab4e28ce3ad7f4c83d5d3e43f1b1d5541cbb2ac1d6f10f7a057046f0e1b","title":"Model routing with a decision model","url":"/docs/features/classifier-router-jev-strategy","content":"Model routing with a decision model\n\nThe classifier router has a jev strategy: one\ndecision-model round trip answers difficulty,\nrequired capabilities, risk and the model pick simultaneously, with a\ncalibrated confidence on each. This page is the strategy's own mechanics —\nclassifier-router.md covers the router as a whole.\n\nThe degradation contract. With no decision provider configured,\nresolveStrategy() resolves auto to heuristic, exactly as it always did.\nclassifyJev() itself never throws: any failure, timeout, or malformed answer\nfalls back to classifyHeuristic(). Configuring a decision provider (for example TYPESAFE_API_KEY or\nAI_GATEWAY_API_KEY) upgrades routing; it cannot make routing worse than before\nthe key existed. The same holds for PERPLEXITY_API_KEY, which is also the\nPerplexity text provider's key, and for CLOUDFLARE_API_KEY with\nCLOUDFLARE_ACCOUNT_ID, which are also the Cloudflare Workers AI text provider's\ntoken and account id. \"Configured\" counts the environment, the instance\ncredentials, and the request's own per-call credentials — a host that holds\nno decision key but passes a tenant's credentials: { laya } on a generate()\ncall routes that call with jev, and the decision goes to the tenant's account.\n\nWhat goes into the state\n\nclassifyJev() sends the request truncated to 8000 characters, plus four\nsignals the caller already has on hand:\n\nAlongside it, one batch asks: difficulty (a choice over the five tiers),\nneeds_vision / needs_tools / needs_reasoning (boolean), risky\n(boolean), context (a score — see\nper-request context budget), and, only when the\npool has more than one member, model (a choice over the pool, rendered by\nthe catalogue). All of this rides in\none request. On TypeSafe that takes ~400ms, because latency is flat in question\ncount; on Perplexity each further question adds about 65 ms, up to 128 (see\nits guide); on\nCloudflare Clef a small request took 0.3 to 1.0 s on 2026-10-03 (see\nits guide). See\nthe batching rule.\n\nThe Cloudflare Clef endpoint ignores state text past about 2,048 tokens, and\nNeuroLink refuses a state it estimates at more than 1,500 tokens with\nmax_tokens_exceeded. A long request is therefore refused there, and the\nheuristic classifier's tier stands, as it does on any failure.\n\nThe difficulty rubric\n\nFive tiers, ordered easiest to hardest, worded about the shape of the work —\nthe model is never told a provider or model name:\n\n| Tier | Criterion |\n| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |\n| trivial | Mechanical and local: rename a symbol, fix a typo, add an import, run one named command, or answer something already stated. |\n| simple | A small localised change or a direct factual answer. One file, one obvious approach. |\n| moderate | Ordinary engineering: implement a well-specified change across a few files, write tests, fix a clearly described bug, review a small diff. |\n| hard | Deep reasoning: architecture and design, debugging a failure whose cause is unknown, security analysis, concurrency, cross-system refactors. |\n| expert | Frontier-level work: ambiguous requirements, novel design with no established pattern, or analysis where a wrong answer is costly and hard to detect. |\n\nAsymmetric confidence bars, and why they differ\n\nA verdict harder than the neutral tier (moderate) spends more if wrong; a\nverdict easier than neutral spends less if wrong. Those are not the same\nmistake:\nRouting a simple task to an expensive model wastes money. Cheap to be wrong\n about, so the bar to route up is low: minUpgradeConfidence defaults to\n 0.3.\nRouting a hard task to a weak model produces a wrong answer. Expensive to be\n wrong about, so the bar to route down is high: minDowngradeConfidence\n defaults to 0.6.\n\nBelow the applicable bar, the difficulty verdict is discarded and the heuristic\nclassifier's tier stands instead — not a downgraded jev answer, the ordinary\nzero-cost fallback.\n\nOne case skips both bars: a risky reading above 0.7 forces the tier to at\nleast hard, unconditionally. Risk can only ever raise the tier, never lower\none, and it is not itself gated by confidence.\n\nAsk about the act, not the subject\n\nThe risk question is not \"does this touch production, money, or credentials\":\n\nCarrying out this request would itself change production, move real money,\nexpose credentials, or alter data that cannot be restored. Writing or testing\ncode that deals with such things, without running it against the real system,\ndoes not count.\n\nThe naive phrasing was tried first and scored high on ordinary code that merely\nconcerns those things — \"add a refund endpoint that calls Stripe\" — which\n","hierarchy":{"lvl0":"Features","lvl1":"Model routing with a decision model","lvl2":"","lvl3":""}},
2627
+ {"objectID":"bd360e5abf4e93403d1fb23a27c946fed1b86d8d8863a98519338332ca726639","title":"Model routing with a decision model","url":"/docs/features/classifier-router-jev-strategy#model-routing-with-a-decision-model","content":"The classifier router has a jev strategy: one\ndecision-model round trip answers difficulty,\nrequired capabilities, risk and the model pick simultaneously, with a\ncalibrated confidence on each. This page is the strategy's own mechanics —\nclassifier-router.md covers the router as a whole.\n\nThe degradation contract. With no decision provider configured,\nresolveStrategy() resolves auto to heuristic, exactly as it always did.\nclassifyJev() itself never throws: any failure, timeout, or malformed answer\nfalls back to classifyHeuristic(). Configuring a decision provider (for example TYPESAFE_API_KEY or\nAI_GATEWAY_API_KEY) upgrades routing; it cannot make routing worse than before\nthe key existed. The same holds for PERPLEXITY_API_KEY, which is also the\nPerplexity text provider's key, and for CLOUDFLARE_API_KEY with\nCLOUDFLARE_ACCOUNT_ID, which are also the Cloudflare Workers AI text provider's\ntoken and account id. \"Configured\" counts the environment, the instance\ncredentials, and the request's own per-call credentials — a host that holds\nno decision key but passes a tenant's credentials: { laya } on a generate()\ncall routes that call with jev, and the decision goes to the tenant's account.","hierarchy":{"lvl0":"Features","lvl1":"Model routing with a decision model","lvl2":"Model routing with a decision model","lvl3":""}},
2628
2628
  {"objectID":"a6b27c365174a477eafb6835b9ab5990c7434acd58cb21534f8419ea21c63dd5","title":"What goes into the state","url":"/docs/features/classifier-router-jev-strategy#what-goes-into-the-state","content":"classifyJev() sends the request truncated to 8000 characters, plus four\nsignals the caller already has on hand:\n\nAlongside it, one batch asks: difficulty (a choice over the five tiers),\nneeds_vision / needs_tools / needs_reasoning (boolean), risky\n(boolean), context (a score — see\nper-request context budget), and, only when the\npool has more than one member, model (a choice over the pool, rendered by\nthe catalogue). All of this rides in\none request. On TypeSafe that takes ~400ms, because latency is flat in question\ncount; on Perplexity each further question adds about 65 ms, up to 128 (see\nits guide); on\nCloudflare Clef a small request took 0.3 to 1.0 s on 2026-10-03 (see\nits guide). See\nthe batching rule.\n\nThe Cloudflare Clef endpoint ignores state text past about 2,048 tokens, and\nNeuroLink refuses a state it estimates at more than 1,500 tokens with\nmax_tokens_exceeded. A long request is therefore refused there, and the\nheuristic classifier's tier stands, as it does on any failure.","hierarchy":{"lvl0":"Features","lvl1":"Model routing with a decision model","lvl2":"What goes into the state","lvl3":""}},
2629
2629
  {"objectID":"ed3d90e1e698e522c2fb4cbd27b81d89a769c3d860bbbb85d004ef5cf1d1090d","title":"The difficulty rubric","url":"/docs/features/classifier-router-jev-strategy#the-difficulty-rubric","content":"Five tiers, ordered easiest to hardest, worded about the shape of the work —\nthe model is never told a provider or model name:\n\n| Tier | Criterion |\n| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |\n| trivial | Mechanical and local: rename a symbol, fix a typo, add an import, run one named command, or answer something already stated. |\n| simple | A small localised change or a direct factual answer. One file, one obvious approach. |\n| moderate | Ordinary engineering: implement a well-specified change across a few files, write tests, fix a clearly described bug, review a small diff. |\n| hard | Deep reasoning: architecture and design, debugging a failure whose cause is unknown, security analysis, concurrency, cross-system refactors. |\n| expert | Frontier-level work: ambiguous requirements, novel design with no established pattern, or analysis where a wrong answer is costly and hard to detect. |","hierarchy":{"lvl0":"Features","lvl1":"Model routing with a decision model","lvl2":"The difficulty rubric","lvl3":""}},
2630
2630
  {"objectID":"2bcf89adce5486bff7cc01f6916f9bf26080de8996ec2277df6e15eb3eb264e3","title":"Asymmetric confidence bars, and why they differ","url":"/docs/features/classifier-router-jev-strategy#asymmetric-confidence-bars-and-why-they-differ","content":"A verdict harder than the neutral tier (moderate) spends more if wrong; a\nverdict easier than neutral spends less if wrong. Those are not the same\nmistake:\nRouting a simple task to an expensive model wastes money. Cheap to be wrong\n about, so the bar to route up is low: minUpgradeConfidence defaults to\n 0.3.\nRouting a hard task to a weak model produces a wrong answer. Expensive to be\n wrong about, so the bar to route down is high: minDowngradeConfidence\n defaults to 0.6.\n\nBelow the applicable bar, the difficulty verdict is discarded and the heuristic\nclassifier's tier stands instead — not a downgraded jev answer, the ordinary\nzero-cost fallback.\n\nOne case skips both bars: a risky reading above 0.7 forces the tier to at\nleast hard, unconditionally. Risk can only ever raise the tier, never lower\none, and it is not itself gated by confidence.","hierarchy":{"lvl0":"Features","lvl1":"Model routing with a decision model","lvl2":"Asymmetric confidence bars, and why they differ","lvl3":""}},
@@ -3224,11 +3224,12 @@
3224
3224
  {"objectID":"e0867ad2f11fe401499dda82ede924767539b8377443f7e7ef3463829da48f72","title":"How the threshold changes the actual budget","url":"/docs/features/context-budget#how-the-threshold-changes-the-actual-budget","content":"resolveHistoryBudget() is what the compactor targets — the model's available\ninput space minus system prompt, current prompt, tool definitions and file\nattachments, all of which ride alongside history rather than being part of\nit. The per-request threshold scales that budget directly:\n\nWith the default 0.8, scale is exactly 1 and the budget is unchanged\nfrom before this option existed. A 0.4 threshold halves the history budget.\nThe 0.95 safety factor is unrelated to this feature — it exists because\ntoken estimation is character-based and approximate, so the compactor always\naims slightly under the true ceiling.","hierarchy":{"lvl0":"Features","lvl1":"Per-request context budget","lvl2":"How the threshold changes the actual budget","lvl3":""}},
3225
3225
  {"objectID":"196b4b8863a944ba130eda4eb2f4fd645841348f85a0647738e81dd3a92df3f0","title":"What this is bad at","url":"/docs/features/context-budget#what-this-is-bad-at","content":"It is a suggestion, not a measurement. The rubric asks \"how much would\n a human say this needs,\" not \"how many tokens will this actually consume.\"\n A request correctly judged recent-turns can still occasionally need one\n detail from much earlier — the invariant above is what keeps that failure\n mode cheap (a slightly early compaction) rather than catastrophic.\nOne judgement per request, not per turn of the conversation that follows.\n If the classifier runs once per turn (which it does), the scope can change\n turn to turn, but there's no persistence of \"this whole session is a\n current-message session\" — a caller who wants that stability should pass\n compactionThreshold explicitly rather than rely on auto.\nIt shares the base model's limits. Everything in\n what decide is bad at\n applies — including that irrelevant state costs accuracy, so a very long\n prompt slice can degrade the scope reading itself.\nNo feedback loop. If the classifier's current-message guess turns out\n wrong and the model asks a follow-up that needed history you already\n dropped, nothing here recovers that turn; the invariant only bounds the\n cost of the guess, it doesn't undo it.","hierarchy":{"lvl0":"Features","lvl1":"Per-request context budget","lvl2":"What this is bad at","lvl3":""}},
3226
3226
  {"objectID":"7764ebf2c6fa54846f789e257b1adea74fb778597e9e2e3767d4410462d2818f","title":"See also","url":"/docs/features/context-budget#see-also","content":"Model routing with a decision model\nRelevance-driven compaction\nThe decide inference type","hierarchy":{"lvl0":"Features","lvl1":"Per-request context budget","lvl2":"See also","lvl3":""}},
3227
- {"objectID":"686e00d8e2675a2d545dd7a7ba18ce36e7ad2aa0bc2aa17b21ecfbfd32697973","title":"Context Compaction","url":"/docs/features/context-compaction","content":"Context Compaction\n\nOverview\n\nNeuroLink's Context Compaction system automatically manages conversation context windows, preventing overflow errors and maintaining conversation quality as sessions grow longer. It runs transparently before every generate() and stream() call.\n\nBefore each LLM call, the Budget Checker estimates the total input tokens needed (system prompt + conversation history + current prompt + tool definitions + file attachments) and compares them against the model's available context window. When usage exceeds the configured threshold (default: 80%), the ContextCompactor runs a 5-stage reduction pipeline:\nRelevance Drop — Ask a decision model which earlier messages the current request still needs (needs a decision provider; skipped without one)\nTool Output Pruning — Replace old tool results with placeholders (cheapest, no LLM call)\nFile Read Deduplication — Keep only the latest read of each file (cheap, no LLM call)\nLLM Summarization — Structured 10-section summary of older messages (expensive, requires LLM call)\nSliding Window Truncation — Remove oldest messages while preserving the first exchange (fallback, no LLM call)\n\nIf a provider still returns a context overflow error after compaction, the system detects it across all supported providers and retries with aggressive compaction.\n\nQuick Start\n\nThat's it. Auto-compaction triggers at 80% context usage with every stage\nenabled.\n\nThe threshold is 80% by default and can be lowered per request by the\ncontext-budget decision — never raised. See\nthat page for why the asymmetry is a hard invariant rather than a tuning\nchoice.\n\nSDK Configuration\n\nThe full contextCompaction block lives inside conversationMemory:\n\n| Field | Type | Default | Description |\n| ----------------------- | --------- | ----------------------------------- | ------------------------------------------------------ |\n| enabled | boolean | true (when summarization enabled) | Master switch for auto-compaction |\n| threshold | number | 0.80 | Usage ratio (0.0–1.0) that triggers compaction |\n| enablePruning | boolean | true | Enable Stage 1: tool output pruning |\n| enableDeduplication | boolean | true | Enable Stage 2: file read deduplication |\n| enableSlidingWindow | boolean | true | Enable Stage 4: sliding window truncation fallback |\n| maxToolOutputBytes | number | 51200 (50 KB) | Maximum tool output size in bytes before truncation |\n| maxToolOutputLines | number | 2000 | Maximum tool output lines before truncation |\n| fileReadBudgetPercent | number | 0.60 | Fraction of remaining context allocated for file reads |\n\nEnvironment Variables\n\nThese environment variables configure conversation memory and summarization, which in turn affect compaction behavior:\n\n| Variable | Default | Description |\n| ---------------------------------- | --------------------------- | ----------------------------------------------------- |\n| NEUROLINK_MEMORY_ENABLED | \"false\" | Set to \"true\" to enable conversation memory |\n| NEUROLINK_SUMMARIZATION_ENABLED | \"true\" | Set to \"false\" to disable summarization |\n| NEUROLINK_TOKEN_THRESHOLD | auto (80% of model context) | Override token threshold for triggering summarization |\n| NEUROLINK_SUMMARIZATION_PROVIDER | \"vertex\" | Provider for summarization LLM calls |\n| NEUROLINK_SUMMARIZATION_MODEL | \"gemini-2.5-flash\" | Model for summarization LLM calls |\n| NEUROLINK_MEMORY_MAX_SESSIONS | 50 | Maximum number of sessions to keep in memory |\n\nSource: src/lib/config/conversationMemory.ts\n\nCLI Flags\n\nThe loop command accepts compaction-specific flags:\n\n| Flag | Type | Default | Description |\n| ---------------------- | --------- | ------- | ---------------------------------------------- |\n| --compact-threshold | number | 0.8 | Context compaction trigger threshold (0.0–1.0) |\n| --disable-compaction | boolean | false | Disable automatic context compaction |\n\nSource: src/cli/factories/commandFactory.ts:1466-1475\n\nPublic API Methods\n\ngetContextStats(sessionId, provider?, model?)\n\nGet context usage statistics for a session. Returns token counts, usage ratio, and whether compaction should trigger.\n\nSignature:\n\nReturns null if conversation memory is not enabled or the session has no messages. The provider defaults to \"openai\" if not specified","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"","lvl3":""}},
3227
+ {"objectID":"686e00d8e2675a2d545dd7a7ba18ce36e7ad2aa0bc2aa17b21ecfbfd32697973","title":"Context Compaction","url":"/docs/features/context-compaction","content":"Context Compaction\n\nOverview\n\nNeuroLink's Context Compaction system automatically manages conversation context windows, preventing overflow errors and maintaining conversation quality as sessions grow longer. It runs transparently before every generate() and stream() call.\n\nBefore each LLM call, the Budget Checker estimates the total input tokens needed (system prompt + conversation history + current prompt + tool definitions + file attachments) and compares them against the model's available context window. When usage exceeds the configured threshold (default: 80%), the ContextCompactor runs a 5-stage reduction pipeline:\nRelevance Drop — Ask a decision model which earlier messages the current request still needs (needs a decision provider; skipped without one)\nTool Output Pruning — Replace old tool results with placeholders (cheapest, no LLM call)\nFile Read Deduplication — Keep only the latest read of each file (cheap, no LLM call)\nLLM Summarization — Structured 10-section summary of older messages (expensive, requires LLM call)\nSliding Window Truncation — Remove oldest messages while preserving the first exchange (fallback, no LLM call)\n\nIf a provider still returns a context overflow error after compaction, the system detects it across all supported providers and retries with aggressive compaction.\n\nQuick Start\n\nThat's it. Auto-compaction triggers at 80% context usage with every stage\nenabled.\n\nThe threshold is 80% by default and can be lowered per request by the\ncontext-budget decision — never raised. See\nthat page for why the asymmetry is a hard invariant rather than a tuning\nchoice.\n\nSDK Configuration\n\nThe full contextCompaction block lives inside conversationMemory:\n\n| Field | Type | Default | Description |\n| ----------------------- | --------- | ----------------------------------- | ------------------------------------------------------ |\n| enabled | boolean | true (when summarization enabled) | Master switch for auto-compaction |\n| threshold | number | 0.80 | Usage ratio (0.0–1.0) that triggers compaction |\n| enablePruning | boolean | true | Enable Stage 1: tool output pruning |\n| enableDeduplication | boolean | true | Enable Stage 2: file read deduplication |\n| enableSlidingWindow | boolean | true | Enable Stage 4: sliding window truncation fallback |\n| maxToolOutputBytes | number | 51200 (50 KB) | Maximum tool output size in bytes before truncation |\n| maxToolOutputLines | number | 2000 | Maximum tool output lines before truncation |\n| fileReadBudgetPercent | number | 0.60 | Fraction of remaining context allocated for file reads |\n\nEnvironment Variables\n\nThese environment variables configure conversation memory and summarization, which in turn affect compaction behavior:\n\n| Variable | Default | Description |\n| ---------------------------------- | --------------------------- | ----------------------------------------------------- |\n| NEUROLINK_MEMORY_ENABLED | \"false\" | Set to \"true\" to enable conversation memory |\n| NEUROLINK_SUMMARIZATION_ENABLED | \"true\" | Set to \"false\" to disable summarization |\n| NEUROLINK_TOKEN_THRESHOLD | auto (80% of model context) | Override token threshold for triggering summarization |\n| NEUROLINK_SUMMARIZATION_PROVIDER | \"vertex\" | Provider for summarization LLM calls |\n| NEUROLINK_SUMMARIZATION_MODEL | \"gemini-2.5-flash\" | Model for summarization LLM calls |\n| NEUROLINK_MEMORY_MAX_SESSIONS | 50 | Maximum number of sessions to keep in memory |\n\nSource: src/lib/config/conversationMemory.ts\n\nReplaying Tool Steps on Later Turns\n\nEvery tool call a turn makes is stored in the session as a tool_call /\ntool_result pair — on both the in-memory and Redis backends, and for\ngenerate() as well as stream(). replayToolSteps decides how those rows\nreach the model on the session's later turns:\n\n| Mode | What the model sees on the next turn |\n| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"","lvl3":""}},
3228
3228
  {"objectID":"09e0674cd3b7a5956fc10a581bddd6dd2d87dcadc5fedf1635d3aaaa330c2f20","title":"Overview","url":"/docs/features/context-compaction#overview","content":"NeuroLink's Context Compaction system automatically manages conversation context windows, preventing overflow errors and maintaining conversation quality as sessions grow longer. It runs transparently before every generate() and stream() call.\n\nBefore each LLM call, the Budget Checker estimates the total input tokens needed (system prompt + conversation history + current prompt + tool definitions + file attachments) and compares them against the model's available context window. When usage exceeds the configured threshold (default: 80%), the ContextCompactor runs a 5-stage reduction pipeline:\nRelevance Drop — Ask a decision model which earlier messages the current request still needs (needs a decision provider; skipped without one)\nTool Output Pruning — Replace old tool results with placeholders (cheapest, no LLM call)\nFile Read Deduplication — Keep only the latest read of each file (cheap, no LLM call)\nLLM Summarization — Structured 10-section summary of older messages (expensive, requires LLM call)\nSliding Window Truncation — Remove oldest messages while preserving the first exchange (fallback, no LLM call)\n\nIf a provider still returns a context overflow error after compaction, the system detects it across all supported providers and retries with aggressive compaction.","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"Overview","lvl3":""}},
3229
3229
  {"objectID":"97b0ee9e95a20df54e288a2c61a91cba08fc356120162ec7d44bb05aecc5bce0","title":"Quick Start","url":"/docs/features/context-compaction#quick-start","content":"That's it. Auto-compaction triggers at 80% context usage with every stage\nenabled.\n\nThe threshold is 80% by default and can be lowered per request by the\ncontext-budget decision — never raised. See\nthat page for why the asymmetry is a hard invariant rather than a tuning\nchoice.","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"Quick Start","lvl3":""}},
3230
3230
  {"objectID":"e0b541cdf70b4e1cf9144b80d7167a1e0168b30fb608aadea1443193a4f2ea58","title":"SDK Configuration","url":"/docs/features/context-compaction#sdk-configuration","content":"The full contextCompaction block lives inside conversationMemory:\n\n| Field | Type | Default | Description |\n| ----------------------- | --------- | ----------------------------------- | ------------------------------------------------------ |\n| enabled | boolean | true (when summarization enabled) | Master switch for auto-compaction |\n| threshold | number | 0.80 | Usage ratio (0.0–1.0) that triggers compaction |\n| enablePruning | boolean | true | Enable Stage 1: tool output pruning |\n| enableDeduplication | boolean | true | Enable Stage 2: file read deduplication |\n| enableSlidingWindow | boolean | true | Enable Stage 4: sliding window truncation fallback |\n| maxToolOutputBytes | number | 51200 (50 KB) | Maximum tool output size in bytes before truncation |\n| maxToolOutputLines | number | 2000 | Maximum tool output lines before truncation |\n| fileReadBudgetPercent | number | 0.60 | Fraction of remaining context allocated for file reads |","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"SDK Configuration","lvl3":""}},
3231
3231
  {"objectID":"126fa67447685cd4b208c851839148a5fd793eb717e84c5a926a41c45d3c43ab","title":"Environment Variables","url":"/docs/features/context-compaction#environment-variables","content":"These environment variables configure conversation memory and summarization, which in turn affect compaction behavior:\n\n| Variable | Default | Description |\n| ---------------------------------- | --------------------------- | ----------------------------------------------------- |\n| NEUROLINK_MEMORY_ENABLED | \"false\" | Set to \"true\" to enable conversation memory |\n| NEUROLINK_SUMMARIZATION_ENABLED | \"true\" | Set to \"false\" to disable summarization |\n| NEUROLINK_TOKEN_THRESHOLD | auto (80% of model context) | Override token threshold for triggering summarization |\n| NEUROLINK_SUMMARIZATION_PROVIDER | \"vertex\" | Provider for summarization LLM calls |\n| NEUROLINK_SUMMARIZATION_MODEL | \"gemini-2.5-flash\" | Model for summarization LLM calls |\n| NEUROLINK_MEMORY_MAX_SESSIONS | 50 | Maximum number of sessions to keep in memory |\n\nSource: src/lib/config/conversationMemory.ts","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"Environment Variables","lvl3":""}},
3232
+ {"objectID":"be1123e35a519364f2b5fde467785ebc16d99628701be4cca4fe6e7b156c2475","title":"Replaying Tool Steps on Later Turns","url":"/docs/features/context-compaction#replaying-tool-steps-on-later-turns","content":"Every tool call a turn makes is stored in the session as a tool_call /\ntool_result pair — on both the in-memory and Redis backends, and for\ngenerate() as well as stream(). replayToolSteps decides how those rows\nreach the model on the session's later turns:\n\n| Mode | What the model sees on the next turn |\n| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| \"marker\" | Default. One compact line per call, folded into the assistant turn: [called lookup_order → ok], → error when the call threw, was rejected or returned an error-shaped result (isError: true, an error field, or a failing status), or → unknown when the result was lost to compaction. |\n| \"full\" | The real tool call and its output, as tool-call / tool-result turns in the provider's own wire shape. A failed call's output carries the error text. |\n| \"off\" | Tool rows are dropped from the prompt; only the surface user / assistant text is replayed. |\n\nSet it on the instance, or per request (the request wins):\n\nCLI loop sessions accept the same knob: /set replayToolSteps full.\n\nWhat to know before choosing \"full\":\nOnly paired rows are replayed.","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"Replaying Tool Steps on Later Turns","lvl3":""}},
3232
3233
  {"objectID":"a9ba3b70b2885e0b6f74fa05e7762bea3073dc07757c04d79b1f66d2e3fcf5b0","title":"CLI Flags","url":"/docs/features/context-compaction#cli-flags","content":"The loop command accepts compaction-specific flags:\n\n`bash","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"CLI Flags","lvl3":""}},
3233
3234
  {"objectID":"5ac5a30da254202ade372d156f845c192254beae8b9cf0d75e75da1f13e687d6","title":"Set a custom compaction threshold (0.0–1.0)","url":"/docs/features/context-compaction#set-a-custom-compaction-threshold-0010","content":"neurolink loop --compact-threshold 0.70","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"Set a custom compaction threshold (0.0–1.0)","lvl3":""}},
3234
3235
  {"objectID":"117126f39d7d75ae18db9cbc8c5d6f532ba55e2ff106904eb0bf770700d47e77","title":"Disable automatic context compaction entirely","url":"/docs/features/context-compaction#disable-automatic-context-compaction-entirely","content":"neurolink loop --disable-compaction\n\n\n| Flag | Type | Default | Description |\n| ---------------------- | --------- | ------- | ---------------------------------------------- |\n| --compact-threshold | number | 0.8 | Context compaction trigger threshold (0.0–1.0) |\n| --disable-compaction | boolean | false | Disable automatic context compaction |\n\nSource: src/cli/factories/commandFactory.ts:1466-1475`","hierarchy":{"lvl0":"Features","lvl1":"Context Compaction","lvl2":"Disable automatic context compaction entirely","lvl3":""}},
@@ -3372,7 +3373,9 @@
3372
3373
  {"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; cloudflare-clef took 0.3 to 1.0 s for a small request on 2026-10-03, and its\nendpoint ignores state text past about 2,048 tokens).\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":""}},
3373
3374
  {"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":""}},
3374
3375
  {"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":""}},
3375
- {"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.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Limits and gotchas","lvl3":""}},
3376
+ {"objectID":"e399806055971566454170aeec7214ec9b5948c8e3a35731a9c64b4ee2be7c21","title":"One funnel for all five sites","url":"/docs/features/decide-inference-type#one-funnel-for-all-five-sites","content":"Every one of those calls is stamped with a site — routing, toolRouting,\ncontextRelevance, summaryGate or ragPlan (the DecisionSite union) — and\ngoes through one private path on NeuroLink, which is also where a bound\ntryDecide() lands. For the four sites that run inside a NeuroLink request —\nrouting, toolRouting, contextRelevance and summaryGate — that path\nforwards the outer generate() / stream() call's per-call credentials,\nabortSignal and requestId (the top-level option, else\ncontext.requestId) to the decision, so a request that carries\ncredentials: { laya: {...} } routes and compacts against that account\nrather than the instance's; for routing the per-call credentials also count\ntowards the auto strategy's activation, so a host that holds no decision key\nitself still routes a request that carries one. ragPlan runs inside a\nhost-wired RAGPipeline, outside any NeuroLink request, so it receives only\nwhat the host puts on the options it hands tryDecide (see \"Host-wired\nconsumers\" below). The path also adds decision.site and\ndecision.host_question_count to the model.decision span; emits\ndecision:before / decision:after on the instance emitter; and runs the\ndecisionHooks described next. Without hooks or listeners, the decision\npayload — state and questions — is unchanged; per-call credentials are still\nforwarded, so the full request on the wire (account, base URL) can differ from\nthe instance's.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"One funnel for all five sites","lvl3":""}},
3377
+ {"objectID":"a472e427cc594fbcc2ea01a87a8ebf99f49ebb52d71a7d5e6ff8baa6667707d1","title":"Riding along: decisionHooks","url":"/docs/features/decide-inference-type#riding-along-decisionhooks","content":"Latency on a decision model is flat in question count, so a host with its own\nquestions about the same request pays nothing to ask them in the round trip\nNeuroLink is already making. decisionHooks on the constructor does exactly\nthat — one request per site, never a second:\n\nWhat the funnel guarantees:\n\n| Concern | Behaviour |\n| ----------------------- |","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Riding along: decisionHooks","lvl3":""}},
3378
+ {"objectID":"fff45cefe577cc88ce4956ce2fbd51677da0f1d953c7c3330d96f4e26737da7e","title":"Reading the limits before you send: decisionLimits()","url":"/docs/features/decide-inference-type#reading-the-limits-before-you-send-decisionlimits","content":"neurolink.decisionLimits({ provider?, model?, credentials? }) returns the\nfigures the pre-flight check compares against, resolved for one model —\nprovider as decide() resolves it, model as model ?? the model decide() sends\n(the one registered for the provider: LAYA_MODEL / TYPESAFE_MODEL as read\nwhen providers were registered, else the default — a later change to the\nvariable moves neither), the per-model entry flattened over the base:\n\nmaxQuestions is present only for a provider that caps by question count\n(Laya); a reading without the key has no count cap, and a host should test\nfor the key rather than compare against Infinity. media is present only\nfor a provider that reads images or video (XOR); its absence is what the\nmedia refusal for TypeSafe and Laya is based on.\n\nenforcedLocally says who refuses: NeuroLink itself, before any network call\n(Laya and XOR, whose servers would silently truncate or fail inside the\nengine), or the provider's server\n(TypeSafe, whose descriptor row is marked advisory and is reported but never\nenforced here — a local refusal would turn a measured server ceiling into a\nclient one that drifts from it). estimateDecisionStateTokens is the very\nfunction the pre-flight refusal uses, so a state it sizes as fitting is sent\nand one it sizes as over is refused; pass the reading so non-ASCII text is\ncharged at the model's measured rate. A named provider is read whether or\nnot it is configured — its limits are facts about the model — while the\ndefault requires a configured provider, as tryDecide() does.\n\nLaya reads far less than Jev. About 768 tokens of state on\ntyped-decisions and multilingual, and 320 on english, auto or an\nunrecognised model name, against Jev's ~33,000. Laya's server does not refuse a\nlonger state; it answers from the first 1,024 tokens (512 on english).","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Reading the limits before you send: decisionLimits()","lvl3":""}},
3376
3379
  {"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":""}},
3377
3380
  {"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":""}},
3378
3381
  {"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":""}},
@@ -3836,34 +3839,38 @@
3836
3839
  {"objectID":"b1f557750d859bc3e2f815e0cd808cd3b3db000e3415abb4dd2088a555db2c5d","title":"Server-specific configuration","url":"/docs/features/mcp-tools-showcase#server-specific-configuration","content":"`","hierarchy":{"lvl0":"Features","lvl1":"MCP Tools Ecosystem - Built-in Tools + Any MCP Server","lvl2":"Server-specific configuration","lvl3":""}},
3837
3840
  {"objectID":"1c1b7104b29baf2ce4b227b583ac9602b2c9ad281aa610df2d47e833e0cf07fd","title":"Custom MCP Server Development","url":"/docs/features/mcp-tools-showcase#custom-mcp-server-development","content":"Create your own MCP server for enterprise integration:\n\nUsing custom server:","hierarchy":{"lvl0":"Features","lvl1":"MCP Tools Ecosystem - Built-in Tools + Any MCP Server","lvl2":"Custom MCP Server Development","lvl3":""}},
3838
3841
  {"objectID":"df814baca8c4887067dca304ed49b9e161ead55743a078c504b4bb98b5bad554","title":"See Also","url":"/docs/features/mcp-tools-showcase#see-also","content":"MCP Integration Guide - Deep dive into MCP architecture\nMCP Server Catalog - Complete MCP server directory\nCustom Tools - Building custom MCP servers\nEnterprise HITL - HITL for tool approval workflows\nInteractive CLI - Using MCP tools in CLI loop mode\nMCP Foundation - MCP architecture documentation","hierarchy":{"lvl0":"Features","lvl1":"MCP Tools Ecosystem - Built-in Tools + Any MCP Server","lvl2":"See Also","lvl3":""}},
3839
- {"objectID":"b72565f6cbc63298b2322018cc2223dbd62c21084467b93c448f8897944c646f","title":"Memory Guide","url":"/docs/features/memory","content":"Memory Guide\n\nSince: v9.12.0 | Status: Stable | Availability: SDK\n\nOverview\n\nNeuroLink includes a memory engine powered by the @juspay/hippocampus SDK. Unlike conversation memory (which tracks recent turns in a session), memory maintains a condensed summary of durable facts about each user across all conversations.\n\nKey characteristics:\nPer-user: Each user gets an independent memory store keyed by userId\nCondensed: Memory is kept to a configurable word limit (default 50 words) via LLM-powered condensation\nPersistent: Stored in S3, Redis, SQLite, or a custom backend — survives server restarts\nNon-blocking: Memory storage happens in the background after each generate/stream call\nCrash-safe: Every SDK method is wrapped in try-catch — errors are logged, never thrown\n\nHow It Works\n\nOn each generate() or stream() call:\nRetrieve: memory.get(userId) fetches the user's condensed memory (if any)\nInject: The memory is prepended to the user's prompt as context\nGenerate: The LLM processes the enhanced prompt normally\nStore: After the response completes, memory.add(userId, content) runs in the background. The SDK sends the old memory + new conversation turn to an LLM which produces a new condensed summary\n\nQuick Start\n\nConfiguration\n\nThe memory field on conversationMemory accepts a Memory object:\n\nRequired Fields\n\n| Field | Type | Description |\n| -------------------- | ------- | ------------------------------------------------------------- |\n| enabled | boolean | Set true to activate memory |\n| storage.type | string | Storage backend: \"s3\", \"redis\", \"sqlite\", or \"custom\" |\n| neurolink.provider | string | AI provider for condensation LLM calls |\n| neurolink.model | string | Model for condensation LLM calls |\n\nOptional Fields\n\n| Field | Type | Default | Description |\n| ------------------ | -------- | -------- | ------------------------------------------------------------------------------------------------------- |\n| maxWords | number | 50 | Maximum words in the condensed memory |\n| prompt | string | built-in | Custom condensation prompt (supports {{OLD_MEMORY}}, {{NEW_CONTENT}}, {{MAX_WORDS}} placeholders) |\n| storage.bucket | string | — | S3 bucket name (required for S3 storage) |\n| storage.prefix | string | — | S3 key prefix for memory objects |\n| storage.url | string | — | Redis connection URL (required for Redis storage) |\n| storage.path | string | — | SQLite file path (required for SQLite storage) |\n| storage.onGet | function | — | Callback to retrieve memory (required for custom storage) |\n| storage.onSet | function | — | Callback to persist memory (required for custom storage) |\n| storage.onDelete | function | — | Callback to delete memory (required for custom storage) |\n| storage.onClose | function | — | Callback for cleanup on close (optional for custom storage) |\n\nStorage Backends\n\nS3 (Recommended for production)\n\nEach user's memory is stored as a single S3 object at {prefix}{userId}.\n\nRedis\n\nSQLite (Development)\n\nNote: SQLite requires the better-sqlite3 optional peer dependency. Install it manually: pnpm add better-sqlite3\n\nHeads up — @juspay/hippocampus is now an optional peer. Starting with this release, NeuroLink no longer pulls @juspay/hippocampus as a hard runtime dependency (the package's own peer on @juspay/neurolink was dragging the deprecated @ai-sdk/google and @ai-sdk/google-vertex packages into the production graph). To enable memory in your app, install the SDK explicitly:\nIf memory is configured but the package is missing, NeuroLink logs a one-time warning and disables memory rather than throwing — generation/streaming continue to work normally.\n\nCustom (Consumer-Managed)\n\nDelegates storage to your application via callbacks. Use this when you want to manage persistence yourself — call your own API, write to your own database, or integrate with any external system.\n\nThe three callbacks (onGet, onSet, onDelete) are required. An optional onClose callback can be provided for cleanup when the SDK shuts down.\n\nExample — file-based storage:\n\nCustom Condensation Prompt\n\nThe condensation prompt controls how the LLM merges old memor","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"","lvl3":""}},
3842
+ {"objectID":"b72565f6cbc63298b2322018cc2223dbd62c21084467b93c448f8897944c646f","title":"Memory Guide","url":"/docs/features/memory","content":"Memory Guide\n\nSince: v9.12.0 | Status: Stable | Availability: SDK\n\nOverview\n\nNeuroLink includes a memory engine powered by the @juspay/hippocampus SDK. Unlike conversation memory (which tracks recent turns in a session), memory maintains a condensed summary of durable facts about each user across all conversations.\n\nKey characteristics:\nPer-user: Each user gets an independent memory store keyed by userId\nCondensed: Memory is kept to a configurable word limit (default 50 words) via LLM-powered condensation\nPersistent: Stored in S3, Redis, SQLite, or a custom backend — survives server restarts\nNon-blocking: Memory storage happens in the background after each generate/stream call\nCrash-safe: Every SDK method is wrapped in try-catch — errors are logged, never thrown\n\nHow It Works\n\nOn each generate() or stream() call:\nRetrieve: memory.get(userId) fetches the user's condensed memory (if any)\nInject: The memory is prepended to the user's prompt as context\nGenerate: The LLM processes the enhanced prompt normally\nStore: After the response completes, memory.add(userId, content) runs in the background. The SDK sends the old memory + new conversation turn to an LLM which produces a new condensed summary\n\nQuick Start\n\nConfiguration\n\nThe memory field on conversationMemory accepts a Memory object:\n\nRequired Fields\n\n| Field | Type | Description |\n| -------------------- | ------- | ------------------------------------------------------------- |\n| enabled | boolean | Set true to activate memory |\n| storage.type | string | Storage backend: \"s3\", \"redis\", \"sqlite\", or \"custom\" |\n| neurolink.provider | string | AI provider for condensation LLM calls |\n| neurolink.model | string | Model for condensation LLM calls |\n\nOptional Fields\n\n| Field | Type | Default | Description |\n| ----------------------- | -------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| maxWords | number | 50 | Maximum words in the condensed memory |\n| prompt | string | built-in | Custom condensation prompt (supports {{OLD_MEMORY}}, {{NEW_CONTENT}}, {{MAX_WORDS}} placeholders). Validated at construction — see Template validation |\n| strictPrompt | boolean | false | When true, a prompt template missing {{OLD_MEMORY}} or {{NEW_CONTENT}} makes the constructor throw instead of disable-and-log (at error) |\n| shouldWrite | function | — | Instance-level write gate — see Write hooks |\n| onBeforeStore | function | — | Instance-level content transform/veto — see Write hooks |\n| client | object | — | A host-managed Hippocampus client (add/get/delete/close). NeuroLink uses it directly instead of loading @juspay/hippocampus |\n| neurolink.credentials | object | inherited | Credentials for the condenser's own NeuroLink instance — see Condenser credentials |\n| neurolink.instance | object | built | A host-supplied condenser ({ generate() }) — see Condenser credentials |\n| storage.bucket | string | — | S3 bucket name (required for S3 storage) |\n| storage.prefix | string | — | S3 key prefix for memory objects |\n| storage.url | string | — | Redis connection URL (required for Redis storage) |\n| storage.path | string | — | SQLite file path (required for SQLite storage) |\n| storage.onGet ","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"","lvl3":""}},
3840
3843
  {"objectID":"fee55f42fe23d44873f198d23a3d749797ef9eaf3a0c659dcf65fc4675c88cca","title":"Memory Guide","url":"/docs/features/memory#memory-guide","content":"Since: v9.12.0 | Status: Stable | Availability: SDK","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Memory Guide","lvl3":""}},
3841
3844
  {"objectID":"0be51b2797131c2d3d0455ac426bc094f6cc6914d3c83d73b0a98819efa7e650","title":"Overview","url":"/docs/features/memory#overview","content":"NeuroLink includes a memory engine powered by the @juspay/hippocampus SDK. Unlike conversation memory (which tracks recent turns in a session), memory maintains a condensed summary of durable facts about each user across all conversations.\n\nKey characteristics:\nPer-user: Each user gets an independent memory store keyed by userId\nCondensed: Memory is kept to a configurable word limit (default 50 words) via LLM-powered condensation\nPersistent: Stored in S3, Redis, SQLite, or a custom backend — survives server restarts\nNon-blocking: Memory storage happens in the background after each generate/stream call\nCrash-safe: Every SDK method is wrapped in try-catch — errors are logged, never thrown","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Overview","lvl3":""}},
3842
3845
  {"objectID":"b42cc7f59b97d46ddac2b44ece700167e61c2f34ba0945232deb20c9f76e07c0","title":"How It Works","url":"/docs/features/memory#how-it-works","content":"On each generate() or stream() call:\nRetrieve: memory.get(userId) fetches the user's condensed memory (if any)\nInject: The memory is prepended to the user's prompt as context\nGenerate: The LLM processes the enhanced prompt normally\nStore: After the response completes, memory.add(userId, content) runs in the background. The SDK sends the old memory + new conversation turn to an LLM which produces a new condensed summary","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"How It Works","lvl3":""}},
3843
3846
  {"objectID":"8b8e3b6898dc68d8b6776cb128395cb465157c527c809e63a9cacf424ed28a2b","title":"Configuration","url":"/docs/features/memory#configuration","content":"The memory field on conversationMemory accepts a Memory object:","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Configuration","lvl3":""}},
3844
3847
  {"objectID":"2a3e9396df3c599c18236bb724662884ddf5719fc133b3b68a2e0d1593b089d7","title":"Required Fields","url":"/docs/features/memory#required-fields","content":"| Field | Type | Description |\n| -------------------- | ------- | ------------------------------------------------------------- |\n| enabled | boolean | Set true to activate memory |\n| storage.type | string | Storage backend: \"s3\", \"redis\", \"sqlite\", or \"custom\" |\n| neurolink.provider | string | AI provider for condensation LLM calls |\n| neurolink.model | string | Model for condensation LLM calls |","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Required Fields","lvl3":""}},
3845
- {"objectID":"92853be87fe18161ce0711e5ad1750da05b2f55d785107abe5a57b42a95159a9","title":"Optional Fields","url":"/docs/features/memory#optional-fields","content":"| Field | Type | Default | Description |\n| ------------------ | -------- | -------- | ------------------------------------------------------------------------------------------------------- |\n| maxWords | number | 50 | Maximum words in the condensed memory |\n| prompt | string | built-in | Custom condensation prompt (supports {{OLD_MEMORY}}, {{NEW_CONTENT}}, {{MAX_WORDS}} placeholders) |\n| storage.bucket | string | — | S3 bucket name (required for S3 storage) |\n| storage.prefix | string | — | S3 key prefix for memory objects |\n| storage.url | string | — | Redis connection URL (required for Redis storage) |\n| storage.path | string | — | SQLite file path (required for SQLite storage) |\n| storage.onGet | function | — | Callback to retrieve memory (required for custom storage) |\n| storage.onSet | function | — | Callback to persist memory (required for custom storage) |\n| storage.onDelete | function | — | Callback to delete memory (required for custom storage) |\n| storage.onClose | function | — | Callback for cleanup on close (optional for custom storage) |","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Optional Fields","lvl3":""}},
3848
+ {"objectID":"92853be87fe18161ce0711e5ad1750da05b2f55d785107abe5a57b42a95159a9","title":"Optional Fields","url":"/docs/features/memory#optional-fields","content":"| Field | Type | Default | Description |\n| ----------------------- | -------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| maxWords | number | 50 | Maximum words in the condensed memory |\n| prompt | string | built-in | Custom condensation prompt (supports {{OLD_MEMORY}}, {{NEW_CONTENT}}, {{MAX_WORDS}} placeholders). Validated at construction — see Template validation |\n| strictPrompt | boolean | false | When true, a prompt template missing {{OLD_MEMORY}} or {{NEW_CONTENT}} makes the constructor throw instead of disable-and-log (at error) |\n| shouldWrite | function | — | Instance-level write gate — see Write hooks |\n| onBeforeStore | function | — | Instance-level content transform/veto — see Write hooks |\n| client | object | — | A host-managed Hippocampus client (add/get/delete/close).","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Optional Fields","lvl3":""}},
3846
3849
  {"objectID":"7060d91086ea22c31cc6be8960bf9412efe2e19666054efd0ab1ab0ae39fad1b","title":"S3 (Recommended for production)","url":"/docs/features/memory#s3-recommended-for-production","content":"Each user's memory is stored as a single S3 object at {prefix}{userId}.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"S3 (Recommended for production)","lvl3":""}},
3847
- {"objectID":"1ae9df351e1c4cc5147fb9d722172b52776ea8b5cff28ee3153c249b7ee57a94","title":"SQLite (Development)","url":"/docs/features/memory#sqlite-development","content":"Note: SQLite requires the better-sqlite3 optional peer dependency. Install it manually: pnpm add better-sqlite3\n\nHeads up — @juspay/hippocampus is now an optional peer. Starting with this release, NeuroLink no longer pulls @juspay/hippocampus as a hard runtime dependency (the package's own peer on @juspay/neurolink was dragging the deprecated @ai-sdk/google and @ai-sdk/google-vertex packages into the production graph). To enable memory in your app, install the SDK explicitly:\nIf memory is configured but the package is missing, NeuroLink logs a one-time warning and disables memory rather than throwing — generation/streaming continue to work normally.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"SQLite (Development)","lvl3":""}},
3850
+ {"objectID":"1ae9df351e1c4cc5147fb9d722172b52776ea8b5cff28ee3153c249b7ee57a94","title":"SQLite (Development)","url":"/docs/features/memory#sqlite-development","content":"Note: SQLite requires the better-sqlite3 optional peer dependency. Install it manually: pnpm add better-sqlite3\n\nHeads up — @juspay/hippocampus is now an optional peer. Starting with this release, NeuroLink no longer pulls @juspay/hippocampus as a hard runtime dependency (the package's own peer on @juspay/neurolink was dragging the deprecated @ai-sdk/google and @ai-sdk/google-vertex packages into the production graph). To enable memory in your app, install the SDK explicitly:\nIf memory is configured but the package is missing, NeuroLink logs a one-time error and disables memory rather than throwing — generation/streaming continue to work normally.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"SQLite (Development)","lvl3":""}},
3848
3851
  {"objectID":"58f5590b0ab3f26aa4ba406587560b8646099c074236afdfb9e178e98a36e634","title":"Custom (Consumer-Managed)","url":"/docs/features/memory#custom-consumer-managed","content":"Delegates storage to your application via callbacks. Use this when you want to manage persistence yourself — call your own API, write to your own database, or integrate with any external system.\n\nThe three callbacks (onGet, onSet, onDelete) are required. An optional onClose callback can be provided for cleanup when the SDK shuts down.\n\nExample — file-based storage:","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Custom (Consumer-Managed)","lvl3":""}},
3849
3852
  {"objectID":"6993f60cffbcdd293e9199cc0730637837c29da7f07653a4fb729752e4638c9d","title":"Custom Condensation Prompt","url":"/docs/features/memory#custom-condensation-prompt","content":"The condensation prompt controls how the LLM merges old memory with new conversation turns. You can provide a custom prompt using the prompt field:","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Custom Condensation Prompt","lvl3":""}},
3850
3853
  {"objectID":"c124defa693b503c17fe3874b067ba5c35e6f8d3cb532c095a9689d8ed007d75","title":"Placeholders","url":"/docs/features/memory#placeholders","content":"| Placeholder | Replaced With |\n| ----------------- | -------------------------------------------------------- |\n| {{OLD_MEMORY}} | The user's existing condensed memory (may be empty) |\n| {{NEW_CONTENT}} | The new conversation turn: \"User: ...\\nAssistant: ...\" |\n| {{MAX_WORDS}} | The configured maxWords value |","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Placeholders","lvl3":""}},
3854
+ {"objectID":"97a32f5918c09ab8af7b41c1ce68fbc2e21fa547dd4b1297d4ffdb3ee2a724d8","title":"Template validation","url":"/docs/features/memory#template-validation","content":"Hippocampus substitutes placeholders with replaceAll and requires none of them, so a typo fails silently at the LLM boundary: a template without {{NEW_CONTENT}} produces a memory that never grows, and one without {{OLD_MEMORY}} overwrites the whole summary on every turn. NeuroLink validates templates before they can do either:\n\n| Template | When it is checked | Missing {{OLD_MEMORY}} or {{NEW_CONTENT}} | Missing only {{MAX_WORDS}} |\n| ------------------------------------------------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------------------- |\n| Instance memory.prompt | new NeuroLink() | Logs at error and disables memory for the instance; with strictPrompt: true the constructor throws | Warns |\n| HC_CONDENSATION_PROMPT (only when no prompt) | new NeuroLink() | Same as above | Warns |\n| Per-call memory.prompt | Inside the background write | Warns once per distinct template and falls back to the instance prompt for that owner | Warns once |\n| additionalUsers[].prompt | Inside the background write | Same as per-call | Warns once |\n\nAn empty or whitespace-only template counts as unset at every level: it is not validated, never disables memory, and is stripped before it reaches Hippocampus — from the constructor config and from every per-call / per-owner add() options.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Template validation","lvl3":""}},
3855
+ {"objectID":"da90fe5068636434a89d19e505f425693ea83aec840ce8cd3d3ed8c6224b366c","title":"Condenser credentials","url":"/docs/features/memory#condenser-credentials","content":"Hippocampus condenses old + new memory through a NeuroLink generate() call. Left to itself it constructs a bare new NeuroLink() for that call — no credentials — so a host that passes provider keys via new NeuroLink({ credentials }) rather than process.env gets a memory that silently never grows (the condensation error is swallowed and the old memory returned).\n\nNeuroLink now hands Hippocampus a dedicated child instance instead:\nIt inherits the parent's credentials (or the explicit memory.neurolink.credentials when set), so condensation works wherever generation works with instance-level credentials. Per-request credentials passed to generate() / stream() do not reach it: the child is built once per instance, and condensation runs after the response, outside the request. A multi-tenant host that holds no instance-level key gets no condensation at all — supply memory.neurolink.credentials, or take over condensation with memory.neurolink.instance.\nIt is a child, not the parent: routing condensation through the parent would run its MCP init, skills and middleware, emit generation:* on the parent emitter and add the condensation cost to the parent's session budget.\nIt has memory disabled, so it can never recurse into a memory write of its own.\nIt is built lazily on the first condensation, never at construction or on a read, so a read-only host pays nothing.\nIt goes with the host: shutdown() and dispose() release it — but only after draining the memory writes already scheduled, bounded by the 30 s write timeout (a write that outlives the bound is left in flight and warned about). A turn's write is deferred to setImmediate, so await nl.generate(…); await nl.shutdown(); — a serverless handler, a per-request instance, a one-shot CLI run — still stores that turn. A write scheduled after the release is skipped (logged at debug) rather than rebuilding the child after its host is gone.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Condenser credentials","lvl3":""}},
3856
+ {"objectID":"33dd21c446906cccc27b0a10b607e3a4ee99011961f6181b2a1241313e4a16e6","title":"Bring your own client","url":"/docs/features/memory#bring-your-own-client","content":"If your application already runs a Hippocampus instance (or anything with the same add/get/delete/close surface), hand it over and NeuroLink will not load or construct @juspay/hippocampus at all. add() and get() are what NeuroLink calls, and both must be functions: a client missing either — a write-only double, say — is refused at initialization with an error log and memory disabled, rather than failing every read silently later. delete() and close() are never called by NeuroLink.\n\nclient may also be a factory — (config) => new Hippocampus(config) — which receives the HippocampusConfig NeuroLink assembled, including the credentialed child under neurolink.instance. That is the way to run your own client class (a subclass, a pinned version, a test double) on exactly what new Hippocampus(config) would get. A plain instance is used as-is: wiring its condenser is then the host's job.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Bring your own client","lvl3":""}},
3851
3857
  {"objectID":"c0fd98956cb5485d5b84393d3946ac3b54d403291c60bbcc0c8bf2b495474bdb","title":"Integration with generate() and stream()","url":"/docs/features/memory#integration-with-generate-and-stream","content":"Memory integrates automatically with both generate() and stream():\nBefore the LLM call: Memory is retrieved and prepended to the input text\nAfter the LLM call: The conversation turn is stored in the background via setImmediate()\nTimeouts: Retrieval has a 3-second timeout; storage has a 10-second timeout (includes LLM condensation)\nErrors are non-blocking: If memory retrieval or storage fails, the generate/stream call continues normally","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Integration with generate() and stream()","lvl3":""}},
3852
3858
  {"objectID":"c184b9ba7f8d9ea96b180123316cf3c06f9ed162f3b7dae201f90201a2b3a3a4","title":"Requirements","url":"/docs/features/memory#requirements","content":"For memory to activate on a call, all three conditions must be met:\nmemory.enabled is true in the config\noptions.context.userId is provided in the generate/stream call\nThe response has non-empty content (for write)","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Requirements","lvl3":""}},
3853
- {"objectID":"38c083ce40f2056421f4d1e8e943fd86e8915dd7c5eac3c3ff42d43597902348","title":"Per-Call Memory Control","url":"/docs/features/memory#per-call-memory-control","content":"When memory is globally enabled, it is active for every generate() and stream() call by default. You can override this behavior on a per-call basis using the memory option without changing the global config.\n\nAvailable flags:\n\n| Flag | Type | Default | Description |\n| --------- | ------- | ------- | ------------------------------------------------------------------ |\n| enabled | boolean | true | Master toggle — when false, both read and write are skipped |\n| read | boolean | true | Whether to read past memory and prepend it to the prompt |\n| write | boolean | true | Whether to write this conversation turn into memory after the call |\n\nNote: These flags only take effect when the global memory SDK is enabled. If global memory is disabled, per-call flags have no effect.\n\nPrecedence:\nGlobal config — Is memory enabled globally? If not, per-call flags are ignored.\nenabled — Master per-call toggle. If false, both read and write are skipped regardless of individual flags.\nread / write — Fine-grained control over individual operations.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Per-Call Memory Control","lvl3":""}},
3859
+ {"objectID":"38c083ce40f2056421f4d1e8e943fd86e8915dd7c5eac3c3ff42d43597902348","title":"Per-Call Memory Control","url":"/docs/features/memory#per-call-memory-control","content":"When memory is globally enabled, it is active for every generate() and stream() call by default. You can override this behavior on a per-call basis using the memory option without changing the global config.\n\nAvailable options (MemoryCallOptions, identical for generate() and stream()):\n\n| Option | Type | Default | Description |\n| ----------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| enabled | boolean | true | Master toggle — when false, both read and write are skipped |\n| read | boolean | true | Whether to read past memory and prepend it to the prompt |\n| write | boolean | true | Whether to write this conversation turn into memory after the call |\n| prompt | string | instance | Condensation prompt for the primary owner on this call.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Per-Call Memory Control","lvl3":""}},
3860
+ {"objectID":"ccd609f94802bab19682a8cc54a82acf679f2c9d2290dcbd0b08445457d51f43","title":"Write hooks: shouldWrite and onBeforeStore","url":"/docs/features/memory#write-hooks-shouldwrite-and-onbeforestore","content":"Two hooks let a host decide whether a turn is remembered and what text reaches the condenser. Both are accepted per call (memory.shouldWrite / memory.onBeforeStore) and on the instance (conversationMemory.memory.shouldWrite / .onBeforeStore). When both are set for the same hook, the per-call one wins for that call — the instance hook is not run.\nshouldWrite runs first. false skips every add() for the turn — the primary owner and all additionalUsers.\nonBeforeStore receives the default \"User: …\\nAssistant: …\" rendering. Return a replacement string, or null to skip the write. The returned string is what every owner's add() receives.\nBoth run inside the deferred background write (after setImmediate), so an async hook never sits on the response path.\nA hook that throws is logged at warn and the write is skipped — a missed memory is recoverable, a polluted condensed summary is not. A non-string, non-null return from onBeforeStore is treated the same way.\n\nFollow-up (not implemented): a decide-powered durability gate — one tryDecide() question per turn (\"does this turn contain a fact worth remembering across conversations?\") wired in as the default shouldWrite when a decision provider is configured, failing open to \"write\" without one, exactly like the other decide consumers. The hook surface above is the seam it would plug into; today the gate is entirely host-defined.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Write hooks: shouldWrite and onBeforeStore","lvl3":""}},
3854
3861
  {"objectID":"5303e216ad007590fcae25e07890a52a671edfc8b95d630a2d28c2d8c9d3a704","title":"Read memory but don't write","url":"/docs/features/memory#read-memory-but-dont-write","content":"Use when you want past context but don't want this call stored — e.g., code review where you'll store a curated summary later.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Read memory but don't write","lvl3":""}},
3855
3862
  {"objectID":"a59a04a159f07b4484483ad50112c1f00c55ee6afc4f7394c9ea0d43c7c03dc6","title":"Write memory but don't read","url":"/docs/features/memory#write-memory-but-dont-read","content":"Use for onboarding or seeding memory without injecting past context into the prompt.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Write memory but don't read","lvl3":""}},
3856
3863
  {"objectID":"1dc7f2785d6d9f3bba49afb12f03235808bae3267834eb947a13b94e1fe2f48f","title":"Skip memory entirely","url":"/docs/features/memory#skip-memory-entirely","content":"Use for operational or utility calls where memory adds noise.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Skip memory entirely","lvl3":""}},
3857
3864
  {"objectID":"328211a0178f83bdefdc9ad52bbbdab3d8b6e0568f491a841975649973a37349","title":"Per-call control with stream()","url":"/docs/features/memory#per-call-control-with-stream","content":"The same memory option works identically in stream().","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Per-call control with stream()","lvl3":""}},
3858
3865
  {"objectID":"052ea05242208609c5a343668642b86cda630a8d0ce7fbbaf9e7906eb77dd9b1","title":"Multi-User Memory","url":"/docs/features/memory#multi-user-memory","content":"Retrieve and store memory for multiple users in a single generate() or stream() call. This enables layered memory — combining a user's personal context with org-level policies, team context, or any other memory scope.\n\nThe primary user is always determined by context.userId. Additional users are specified via memory.additionalUsers. Memory for all users (primary + additional) is fetched and stored in parallel.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Multi-User Memory","lvl3":""}},
3859
3866
  {"objectID":"41766b5e87dd4af3c868d4da711a436fb49df716bcccf1bc38f3ced7c310571f","title":"Context Format","url":"/docs/features/memory#context-format","content":"When multiple users' memories are retrieved, they are formatted with labels and injected into the prompt:\n\nThe primary user's label is always \"User\". Additional users use the label field, falling back to userId if not set.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Context Format","lvl3":""}},
3860
- {"objectID":"23c766abdc2d392afbf77fe2bb5e3144b52ee00eb0b4256aa546f3dd12686c79","title":"Per-User Condensation","url":"/docs/features/memory#per-user-condensation","content":"Each additional user can specify a custom prompt and maxWords for its condensation strategy. This is useful when different memory scopes need different extraction rules — e.g. personal preferences vs compliance policies.\n\nThe prompt must include {{OLD_MEMORY}}, {{NEW_CONTENT}}, and {{MAX_WORDS}} placeholders. See Custom Condensation Prompt for details.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Per-User Condensation","lvl3":""}},
3867
+ {"objectID":"23c766abdc2d392afbf77fe2bb5e3144b52ee00eb0b4256aa546f3dd12686c79","title":"Per-User Condensation","url":"/docs/features/memory#per-user-condensation","content":"Each additional user can specify a custom prompt and maxWords for its condensation strategy. This is useful when different memory scopes need different extraction rules — e.g. personal preferences vs compliance policies.\n\nThe prompt must include {{OLD_MEMORY}} and {{NEW_CONTENT}} (and should include {{MAX_WORDS}}). A per-user template missing either structural placeholder is logged once and that user falls back to the instance prompt — see Template validation. The primary owner's prompt is set with the per-call memory.prompt instead — see Per-Call Memory Control.","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Per-User Condensation","lvl3":""}},
3861
3868
  {"objectID":"5fdc2424ba7edebb39b0a0ccb3687e281fb6133a6ab4f0b3b035c51e5201a7f4","title":"Selective Read/Write","url":"/docs/features/memory#selective-readwrite","content":"Control which additional users participate in read and write independently:","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Selective Read/Write","lvl3":""}},
3862
- {"objectID":"3a53ed9865e1315f6b30c67dbff92db8c16ef142453305ce1b6d600da612d189","title":"AdditionalMemoryUser Options","url":"/docs/features/memory#additionalmemoryuser-options","content":"| Field | Type | Default | Description |\n| ---------- | ------- | -------- | ----------------------------------------------------- |\n| userId | string | required | The owner ID to retrieve/store memory for |\n| label | string | userId | Label used in the formatted memory context |\n| read | boolean | true | Whether to read this user's memory |\n| write | boolean | true | Whether to write conversation into this user's memory |\n| prompt | string | default | Custom condensation prompt for this user |\n| maxWords | number | default | Max words for this user's condensed memory |","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"AdditionalMemoryUser Options","lvl3":""}},
3869
+ {"objectID":"3a53ed9865e1315f6b30c67dbff92db8c16ef142453305ce1b6d600da612d189","title":"AdditionalMemoryUser Options","url":"/docs/features/memory#additionalmemoryuser-options","content":"| Field | Type | Default | Description |\n| ---------- | ------- | -------- | -------------------------------------------------------------------------------------------------- |\n| userId | string | required | The owner ID to retrieve/store memory for |\n| label | string | userId | Label used in the formatted memory context |\n| read | boolean | true | Whether to read this user's memory |\n| write | boolean | true | Whether to write conversation into this user's memory |\n| prompt | string | instance | Custom condensation prompt for this user (validated; falls back to the instance prompt when fatal) |\n| maxWords | number | instance | Max words for this user's condensed memory |","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"AdditionalMemoryUser Options","lvl3":""}},
3863
3870
  {"objectID":"b005f5801f2e437fb84824bcdb6105404b6bb0fc26741dd0e8ce26302eec8ad7","title":"Environment Variables","url":"/docs/features/memory#environment-variables","content":"The @juspay/hippocampus SDK reads these environment variables:\n\n| Variable | Default | Description |\n| ------------------------ | -------- | ----------------------------------------------------------- |\n| HC_LOG_LEVEL | warn | SDK log level: debug, info, warn, error |\n| HC_CONDENSATION_PROMPT | built-in | Default condensation prompt (overridden by config prompt) |","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Environment Variables","lvl3":""}},
3864
3871
  {"objectID":"e3d5c46dd54876f9d88dbfb23dd9bad2c393329957e7d4f75a39b7ef8aa06fd2","title":"Error Handling","url":"/docs/features/memory#error-handling","content":"The memory SDK is designed to never crash the host application:\nEvery public method (get(), add(), delete(), close()) is wrapped in try-catch\nErrors are logged via logger.warn() and safe defaults are returned\nget() returns null on error\nadd() silently fails on error\nStorage initialization errors result in memory being disabled (returns null from ensureMemoryReady())","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Error Handling","lvl3":""}},
3865
3872
  {"objectID":"bb1474a8e343799496d81b93fb591a24417ce87e53aa8db8a83788310103d902","title":"Type Exports","url":"/docs/features/memory#type-exports","content":"NeuroLink re-exports the memory types for use in host applications:","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"Type Exports","lvl3":""}},
3866
- {"objectID":"58b3d361e91f40985729c568ce2b68260730fafac985ed726083beb3bdd32256","title":"See Also","url":"/docs/features/memory#see-also","content":"Conversation Memory - Session-based conversation history\nMemory Integration - Advanced hippocampus configuration and patterns\nContext Compaction - Automatic context window management\nContext Summarization - Conversation compression","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"See Also","lvl3":""}},
3873
+ {"objectID":"58b3d361e91f40985729c568ce2b68260730fafac985ed726083beb3bdd32256","title":"See Also","url":"/docs/features/memory#see-also","content":"Conversation Memory - Session-based conversation history\nMemory Integration - Advanced hippocampus configuration and patterns\nContext Compaction - Automatic context window management\nContext Summarization - Conversation compression\nPer-Request Credentials - How credentials flow to providers. Only instance-level credentials (or memory.neurolink.credentials) reach the memory condenser; per-request credentials do not","hierarchy":{"lvl0":"Features","lvl1":"Memory Guide","lvl2":"See Also","lvl3":""}},
3867
3874
  {"objectID":"c07221ea62db3c1a2b47f2d540dfef04563cd63dda1cb4ecef74e86e0941d6cd","title":"Multimodal Chat Experiences","url":"/docs/features/multimodal-chat","content":"Multimodal Chat Experiences\n\nNeuroLink provides full multimodal pipelines so you can mix text, URLs, and local images in a single interaction. The CLI, SDK, and loop sessions all use the same message builder, ensuring parity across workflows.\n\nVideo Generation {#video-generation}\n\nNeuroLink supports video generation from images using Google's Veo 3.1 model via Vertex AI. Transform static images into 8-second videos with synchronized audio.\n\nSee: Video Generation Guide for complete documentation.\n\nPPT Generation {#ppt-generation}\n\nNeuroLink supports AI-powered PowerPoint generation from text prompts. Create professional presentations with 35 slide types, 5 themes, and optional AI-generated images.\n\nSee: PPT Generation Guide for complete documentation.\n\nImages {#images}\n\nNeuroLink provides comprehensive image support across all vision-capable providers. Images can be provided as local file paths, HTTPS URLs, or Buffer objects, and are automatically converted to the provider's required encoding format.\n\nWhat You Get\nUnified CLI flag – --image accepts multiple file paths or HTTPS URLs per request.\nSDK parity – pass input.images (buffers, file paths, or URLs) and stream structured outputs.\nProvider fallbacks – orchestration automatically retries compatible multimodal models.\nStreaming support – neurolink stream renders partial responses while images upload in the background.\n\nThe image input accepts three formats: Buffer objects (from readFileSync), local file paths (relative or absolute), or HTTPS URLs. All formats are automatically converted to the provider's required encoding.\n\nSupported Providers & Models\n\nNot all providers support multimodal inputs. Verify your chosen model has the vision capability using npx @juspay/neurolink models list --capability vision. Unsupported providers will return an error or ignore image inputs.\n\n| Provider | Recommended Models | Notes |\n| ---------------------- | ---------------------------------------- | --------------------------------------------------------- |\n| google-ai, vertex | gemini-2.5-pro, gemini-2.5-flash | Local files and URLs supported. |\n| openai, azure | gpt-4o, gpt-4o-mini | Requires OPENAI_API_KEY or Azure deployment name + key. |\n| anthropic, bedrock | claude-3.5-sonnet, claude-3.7-sonnet | Bedrock needs region + credentials. |\n| litellm | Any upstream multimodal model | Ensure LiteLLM server exposes vision capability. |\n\nUse npx @juspay/neurolink models list --capability vision to see the full list from config/models.json.\n\nPrerequisites\nProvider credentials with vision/multimodal permissions.\nLatest CLI (npm, pnpm, or npx) or SDK.\nOptional: Redis if you want images stored alongside loop-session history.\n\nCLI Quick Start\n\nStreaming & Loop Sessions\n\nSDK Usage\nEnable provider orchestration for automatic multimodal fallbacks\nText prompt describing what you want from the images\nArray of images in multiple formats\nLocal file as Buffer (auto-converted to base64)\nRemote URL (downloaded and encoded automatically)\nChoose a vision-capable provider\nOptionally evaluate the quality of multimodal responses\n\nImage Alt Text for Accessibility\n\nNeuroLink supports alt text for images, which is helpful for accessibility (screen readers) and providing additional context to AI models. Alt text is automatically included as context in the prompt sent to AI providers.\nImages can be objects with data and altText properties\nAlt text for local file - helps AI understand the image context\nAlt text for remote URL - provides additional context for accessibility\n\nYou can also mix simple images with alt-text-enabled images:\n\nKeep alt text concise but descriptive (under 125 characters is ideal)\nFocus on the key information the image conveys\nAlt text is automatically included as context in the prompt, helping AI models better understand the images\n :::\n\nUse stream() with the same structure when you need incremental tokens:\nAccepts file path, Buffer, or HTTPS URL\nOpenAI's GPT-4o and GPT-4o-mini support vision\nStream text responses while image uploads in background\n\nConfiguration & Tuning\nImage sources – Local paths are resolved relative to process.cwd(). URLs must be HTTPS.\nSize limits – Providers cap images at ~20 MB. Resize or compress large assets before sending.\nMultiple images – Order matters; the builder interleaves captions in the order provided.\nRegion routing – Set region on each request (e.g., us-east-1) for providers that enforce locality.\nLoop sessions – Images uploaded during loop are cached per session; call clear session to reset.\nAlt text – Add alt text to images for accessibility; the text is included as context for AI models.\n\nBest Practices\nProvide short captions in the prompt describing each image (e.g., \"see before.png on the left\").\nUse alt text for images that convey important ","hierarchy":{"lvl0":"Features","lvl1":"Multimodal Chat Experiences","lvl2":"","lvl3":""}},
3868
3875
  {"objectID":"4660ba8c07ff51115ed9aa6c87a424bfd5b8b0f54e27ce28ac6875a5560e1c25","title":"Multimodal Chat Experiences","url":"/docs/features/multimodal-chat#multimodal-chat-experiences","content":"NeuroLink provides full multimodal pipelines so you can mix text, URLs, and local images in a single interaction. The CLI, SDK, and loop sessions all use the same message builder, ensuring parity across workflows.","hierarchy":{"lvl0":"Features","lvl1":"Multimodal Chat Experiences","lvl2":"Multimodal Chat Experiences","lvl3":""}},
3869
3876
  {"objectID":"803ac5330bf8e75d40d76e9e663d67c06e59b49b136f2ad1a8c60d52f5c718cb","title":"Video Generation","url":"/docs/features/multimodal-chat#video-generation","content":"NeuroLink supports video generation from images using Google's Veo 3.1 model via Vertex AI. Transform static images into 8-second videos with synchronized audio.\n\nSee: Video Generation Guide for complete documentation.","hierarchy":{"lvl0":"Features","lvl1":"Multimodal Chat Experiences","lvl2":"Video Generation","lvl3":""}},
@@ -4527,9 +4534,10 @@
4527
4534
  {"objectID":"e3dffe1fb95f6705f2d355f61f0d8a7f3053c312f576aaf17f4a82c3d03e9953","title":"Voice Discovery","url":"/docs/features/tts#voice-discovery","content":"--tts-voice takes a provider-specific identifier, and neurolink voices\nprints the ones a provider will accept:\n\n--provider is required. The list is sorted by name and the count is printed\nat the end. Providers are registered only when their credentials are present,\nso an unconfigured provider is reported the same way a misspelled one is —\nwith the set that is registered named in the message, and a non-zero exit.\n\nThe same list is available from the SDK:\n\nlanguageCode is passed through to the provider, which decides what filtering\nit means: Google and Azure query their APIs with it, and OpenAI's fixed list\nignores it. An unregistered provider, or one whose handler does not implement\nvoice listing, raises a TTS_PROVIDER_NOT_SUPPORTED error.\n\nGoogle voice identifiers follow Google Cloud TTS naming conventions: <language>-<variant>-<type>-<name> (e.g., en-US-Neural2-C, en-GB-Wavenet-D).\n\nRefer to the Google Cloud TTS voice list for all available voices.","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Voice Discovery","lvl3":""}},
4528
4535
  {"objectID":"5286e5a8d6c113fc69be8b99e4bb873edd71e451caa2a01673aa1d31621f0af3","title":"Supported Languages","url":"/docs/features/tts#supported-languages","content":"English Variants:\nen-US - United States English\nen-GB - British English\nen-AU - Australian English\nen-IN - Indian English\n\nOther Languages:\nes-ES, es-US - Spanish (Spain, Latin America)\nfr-FR, fr-CA - French (France, Canada)\nde-DE - German\nja-JP - Japanese\nhi-IN - Hindi\nzh-CN, zh-TW - Chinese (Simplified, Traditional)\npt-BR, pt-PT - Portuguese (Brazil, Portugal)\nit-IT - Italian\nko-KR - Korean\nru-RU - Russian","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Supported Languages","lvl3":""}},
4529
4536
  {"objectID":"cc003baac54d52f5303fa3e333d43096212de9505d8cb3f15a14c96f3e563e42","title":"Voice Selection Guidelines","url":"/docs/features/tts#voice-selection-guidelines","content":"For Natural Conversations:\n\nFor Professional Narration:\n\nFor Cost Optimization:","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Voice Selection Guidelines","lvl3":""}},
4530
- {"objectID":"e6d89ecb1a2aedf5e505263b9c14c576c12f543bd8ea95343f7411a4fa1b3b59","title":"TTS Synthesis Modes","url":"/docs/features/tts#tts-synthesis-modes","content":"NeuroLink supports two TTS synthesis modes:","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"TTS Synthesis Modes","lvl3":""}},
4531
- {"objectID":"d8ca58f6ac098033093598302f1e69abd064e002baf5f625f913075b2877bb44","title":"Mode 1: Direct Text-to-Speech (Default)","url":"/docs/features/tts#mode-1-direct-text-to-speech-default","content":"Converts input text directly to speech without AI generation.\n\nUse cases:\nPre-written scripts\nSystem notifications\nFixed announcements\nVoice confirmations","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Mode 1: Direct Text-to-Speech (Default)","lvl3":""}},
4532
- {"objectID":"e5925261019d9e2b26a349cf4cde490438d5b9f49eaa2f82f562c04f9df25663","title":"Mode 2: AI Response Synthesis","url":"/docs/features/tts#mode-2-ai-response-synthesis","content":"Generates AI response first, then converts the response to speech.\n\nNote: when useAiResponse: true, NeuroLink synthesizes the chat\nprovider's text response. If your chat provider has no TTS counterpart\n(e.g. anthropic, bedrock), set tts.provider explicitly — otherwise\nstreaming continues as text-only and logs a provider-resolution warning.\nChat providers that double as TTS handlers (e.g. google-ai, vertex)\nauto-resolve when tts.provider is omitted.\n\nUse cases:\nVoice assistants\nInteractive AI conversations\nDynamic content narration\nAI-powered podcasts","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Mode 2: AI Response Synthesis","lvl3":""}},
4537
+ {"objectID":"e6d89ecb1a2aedf5e505263b9c14c576c12f543bd8ea95343f7411a4fa1b3b59","title":"TTS Synthesis Modes","url":"/docs/features/tts#tts-synthesis-modes","content":"NeuroLink supports two TTS synthesis modes, selected with tts.mode:\n\n| tts.mode | What is spoken | Model call | usage |\n| -------------------- | --------------------------------- | ---------- | --------- |\n| \"direct\" (default) | the input text / prompt, verbatim | none | all zeros |\n| \"response\" | the model's generated reply | yes | real |\n\nresult.ttsMetadata.mode reports which one ran. The older\nuseAiResponse: true flag still means mode: \"response\" and is still\nhonoured, but an explicit mode wins when both are present. stream()\nalways synthesizes the streamed reply and ignores mode.","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"TTS Synthesis Modes","lvl3":""}},
4538
+ {"objectID":"d8ca58f6ac098033093598302f1e69abd064e002baf5f625f913075b2877bb44","title":"Mode 1: Direct Text-to-Speech (Default)","url":"/docs/features/tts#mode-1-direct-text-to-speech-default","content":"Converts input text directly to speech without AI generation.\n\nDirect mode ignores LLM options. Because no model is called, tools,\nsystemPrompt, conversationMessages, schema and\nconversationMemoryConfig have no effect. If a request carries any of them\nwithout an explicit tts.mode, NeuroLink logs one warning naming the\nignored options — the usual fix is mode: \"response\". The request is never\nrejected, so existing \"speak this text\" callers are unaffected.\n\nUse cases:\nPre-written scripts\nSystem notifications\nFixed announcements\nVoice confirmations","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Mode 1: Direct Text-to-Speech (Default)","lvl3":""}},
4539
+ {"objectID":"e5925261019d9e2b26a349cf4cde490438d5b9f49eaa2f82f562c04f9df25663","title":"Mode 2: AI Response Synthesis","url":"/docs/features/tts#mode-2-ai-response-synthesis","content":"Generates AI response first, then converts the response to speech.\n\nNote: when mode: \"response\", NeuroLink synthesizes the chat\nprovider's text response. If your chat provider has no TTS counterpart\n(e.g. anthropic, bedrock), set tts.provider explicitly — otherwise\nstreaming continues as text-only and logs a provider-resolution warning.\nChat providers that double as TTS handlers (e.g. google-ai, vertex)\nauto-resolve when tts.provider is omitted.\n\nUse cases:\nVoice assistants\nInteractive AI conversations\nDynamic content narration\nAI-powered podcasts","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Mode 2: AI Response Synthesis","lvl3":""}},
4540
+ {"objectID":"865372dc1e3474adbdcb43626b94cb0f14ccaf277968173ad2ed0f2758566980","title":"Cleaning text for speech (tts.sanitize)","url":"/docs/features/tts#cleaning-text-for-speech-ttssanitize","content":"Model output is written for a screen. Read aloud, **bold** becomes\n\"asterisk asterisk\", a URL is spelled out letter by letter, and an emoji is\nannounced by name. tts.sanitize runs the text through\nprepareTextForSpeech() first:\n\nWith sanitize: true the defaults apply; pass an object to tune them:\n\n| Option | Default | Effect |\n| ----------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------ |\n| markdown | true | Strip headings, emphasis, inline code, bullets, blockquotes, HTML tags; tables become comma-separated rows; links → text |\n| codeBlocks | \"phrase\" | Fenced code: \"phrase\" speaks codeBlockPhrase, \"drop\" removes it, \"keep\" reads the contents |\n| codeBlockPhrase | \"Code block omitted.\" | Spoken stand-in for a fenced block |\n| urls | \"hostname\" | https://docs.example.com/a/b → docs.example.com (an IDN host in Unicode, not punycode); \"remove\" drops the URL |\n| emoji | true | Remove emoji and pictographs with their skin-tone modifiers, variation selectors and the joiners between them |\n\nIt is off by default: existing callers get byte-identical synthesis\ninput. The pass is careful about what it does not touch:\nEmphasis is a pair around a word run — **bold**, *it*, _this_ — so\n an asterisk between digits is arithmetic and stays: 2*3*4 = 24 is spoken\n as written, as is *123*1#. Backslash escapes are resolved first and the\n escaped character is kept: \\*not bold\\* becomes *not bold*.\nOnly real HTML tag names are stripped (<b>, <br/>, <a href>, …).","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Cleaning text for speech (tts.sanitize)","lvl3":""}},
4533
4541
  {"objectID":"5a29b541a3064061eeef699881191d31870319cde04f276c32e8d367a62050c8","title":"Supported Formats","url":"/docs/features/tts#supported-formats","content":"| Format | Quality | File Size | Platform Support | Use Case |\n| ------------ | ------- | -------------------- | ---------------- | ------------------------------ |\n| MP3 | Good | Small (~100 KB/min) | All platforms | Default, balanced quality/size |\n| WAV | Best | Large (~1 MB/min) | All platforms | Highest quality, editing |\n| OGG/Opus | Good | Medium (~150 KB/min) | macOS, Linux | Web streaming |","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Supported Formats","lvl3":""}},
4534
4542
  {"objectID":"44c2bba047e528949d8147281bcafb92081d1f66178d2a88eb3363b08c187857","title":"Platform-Specific Considerations","url":"/docs/features/tts#platform-specific-considerations","content":"Windows:\nBuilt-in playback only supports WAV format\nAuto-converts to WAV when play: true on Windows\nUse MP3 for file output, WAV for immediate playback\n\nmacOS:\nafplay (built-in) decodes every format — no setup needed.\n\nLinux:\nWAV requires ALSA (aplay) or PulseAudio (paplay), but no compressed-format decoder.\nCompressed formats (mp3/ogg/opus) need a real decoder — NeuroLink tries ffplay (ffmpeg), then mpv, mpg123 (mp3), then cvlc (VLC), in that order. Install any one of them.\npaplay/aplay cannot decode mp3, so with none of the above installed a default --tts-play (which defaults to mp3) will report a clear error naming the decoders — or use --tts-format wav when aplay or paplay is available.","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Platform-Specific Considerations","lvl3":""}},
4535
4543
  {"objectID":"f81c0fdbf9f1f3229321c4a9993f05ab420862d24a1af83db8ec574a732065dd","title":"Speaking Rate","url":"/docs/features/tts#speaking-rate","content":"Control speech speed (0.25 to 4.0):\n\nCLI:","hierarchy":{"lvl0":"Features","lvl1":"Text-to-Speech (TTS) Integration Guide","lvl2":"Speaking Rate","lvl3":""}},
@@ -4835,12 +4843,15 @@
4835
4843
  {"objectID":"5cd4974f081636e75ea80229d91262d701b573b68056a96baa5a5874e7cf5c98","title":"16. OpenAI TTS","url":"/docs/getting-started/environment-variables#16-openai-tts","content":"OpenAI TTS uses the same OPENAI_API_KEY as the OpenAI LLM provider. No additional credentials are required.","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"16. OpenAI TTS","lvl3":""}},
4836
4844
  {"objectID":"909795db57326a3ecef834860b94aa18841778b1c5c5f655de70320be80d7e1f","title":"How to Get the API Key","url":"/docs/getting-started/environment-variables#how-to-get-the-api-key","content":"See OpenAI above — the same key is used for both LLM and TTS.","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"How to Get the API Key","lvl3":""}},
4837
4845
  {"objectID":"967b4dc5c4a65df23f4278294f9441c5a27d205a26b02a18c773327e218c2e63","title":"Supported Models","url":"/docs/getting-started/environment-variables#supported-models-12","content":"tts-1 (default) - Optimized for speed\ntts-1-hd - Optimized for audio quality","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"Supported Models","lvl3":""}},
4846
+ {"objectID":"185e100a3b4e0b32579458a78f8486c9aabc327d67ab250d7f4cda82375ff014","title":"Required Variables","url":"/docs/getting-started/environment-variables#required-variables-14","content":"One key serves the elevenlabs TTS handler, the elevenlabs-stt (Scribe)\nSTT handler and elevenlabs-music.","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"Required Variables","lvl3":""}},
4847
+ {"objectID":"4e82400622bb2abfeb732ebcf3cb0b55193149d88102d9ed6c7847ea64c245da","title":"Optional Variables","url":"/docs/getting-started/environment-variables#optional-variables-16","content":"`bash","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"Optional Variables","lvl3":""}},
4848
+ {"objectID":"6cab8f5cceb9379d1b194ee1aa79df23bfdf554c1b884793c82f646f572adaea","title":"API base URL including the /v1 prefix — for a proxy or a test stub.","url":"/docs/getting-started/environment-variables#api-base-url-including-the-v1-prefix-for-a-proxy-or-a-test-stub","content":"ELEVENLABSBASEURL=\"https://api.elevenlabs.io/v1\"\n`","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"API base URL including the /v1 prefix — for a proxy or a test stub.","lvl3":""}},
4838
4849
  {"objectID":"712d471a61dd85b77d43664ed486e4f994254cb769334ff8be588ab27253b4b5","title":"How to Get ElevenLabs API Key","url":"/docs/getting-started/environment-variables#how-to-get-elevenlabs-api-key","content":"Visit ElevenLabs\nSign up or log in to your account\nNavigate to Profile → API Key\nCopy the key","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"How to Get ElevenLabs API Key","lvl3":""}},
4839
- {"objectID":"8a691f68a37b176e79af81531236feaf5a09e66aa6ad53cf417b1f841145ee93","title":"Supported Models","url":"/docs/getting-started/environment-variables#supported-models-13","content":"eleven_multilingual_v2 (default) - Best quality, 29 languages\neleven_turbo_v2_5 - Low-latency streaming, 32 languages\neleven_flash_v2_5 - Fastest, suitable for real-time use","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"Supported Models","lvl3":""}},
4850
+ {"objectID":"8a691f68a37b176e79af81531236feaf5a09e66aa6ad53cf417b1f841145ee93","title":"Supported Models","url":"/docs/getting-started/environment-variables#supported-models-13","content":"eleven_multilingual_v2 (default) - Best quality, 29 languages\neleven_v3 - Most expressive, 70+ languages, accepts language\neleven_turbo_v2_5 - Low-latency streaming, 32 languages, accepts language\neleven_flash_v2_5 - Fastest, suitable for real-time use, accepts language\neleven_flash_v2, eleven_turbo_v2, eleven_monolingual_v1 - English variants\nSTT: scribe_v2 (default), scribe_v2_medical; scribe_v1 and scribe_v1_experimental are deprecated\n\nSee the ElevenLabs provider guide\nfor formats (Opus 48 kHz for ogg/opus), speed clamping, retries and the\nScribe STT options.","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"Supported Models","lvl3":""}},
4840
4851
  {"objectID":"9129ffd649ccffb4b060645ec37e6d3fc8d82f8a2a9bd7c017fb0f0b55353973","title":"How to Get Deepgram API Key","url":"/docs/getting-started/environment-variables#how-to-get-deepgram-api-key","content":"Visit Deepgram Console\nSign up or log in to your account\nNavigate to API Keys\nClick Create a New API Key\nCopy the key","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"How to Get Deepgram API Key","lvl3":""}},
4841
4852
  {"objectID":"68132ecc90d03a81b52c2efbc9cc986bcd0d639606e64874b1d1e5f0e2321d7d","title":"Supported Models","url":"/docs/getting-started/environment-variables#supported-models-14","content":"nova-3 (default) - Latest, highest accuracy\nnova-2 - High accuracy, broad language support\nbase - Balanced accuracy and speed","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"Supported Models","lvl3":""}},
4842
4853
  {"objectID":"c2064d0829d78a9a62faf77148fdbb940768b075e7cf88ec239a35262b759ed5","title":"19. Azure Speech Services (TTS + STT)","url":"/docs/getting-started/environment-variables#19-azure-speech-services-tts-stt","content":"Azure Speech Services provides both text-to-speech and speech-to-text through Microsoft Azure Cognitive Services.","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"19. Azure Speech Services (TTS + STT)","lvl3":""}},
4843
- {"objectID":"4e82400622bb2abfeb732ebcf3cb0b55193149d88102d9ed6c7847ea64c245da","title":"Optional Variables","url":"/docs/getting-started/environment-variables#optional-variables-16","content":"If you also use Google STT or Gemini Live alongside Azure, set the canonical\nGoogle credentials:\n\n`bash\nGOOGLEAIAPI_KEY=\"AIza-your-google-ai-studio-key\" # canonical","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"Optional Variables","lvl3":""}},
4854
+ {"objectID":"41a0a0548820563db26fdc455f54323fdff3c188c0f268ff9891bc56806e0f7e","title":"Optional Variables","url":"/docs/getting-started/environment-variables#optional-variables-17","content":"If you also use Google STT or Gemini Live alongside Azure, set the canonical\nGoogle credentials:\n\n`bash\nGOOGLEAIAPI_KEY=\"AIza-your-google-ai-studio-key\" # canonical","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"Optional Variables","lvl3":""}},
4844
4855
  {"objectID":"7bec731e65dbc6430ed02e8400c47ccfec5344c1af270765439efc1d73fdbb5b","title":"GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa.json # service account (Google STT)","url":"/docs/getting-started/environment-variables#google_application_credentialspathtosajson-service-account-google-stt","content":"`","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa.json # service account (Google STT)","lvl3":""}},
4845
4856
  {"objectID":"3f1d029c9cf99acb82aebeaf36d531ac671907399d2136e1ea5bf00e6e03ed65","title":"How to Set Up Azure Speech Services","url":"/docs/getting-started/environment-variables#how-to-set-up-azure-speech-services","content":"Sign in to Azure Portal\nCreate a Speech resource under Azure AI services\nGo to Keys and Endpoint in your Speech resource\nCopy Key 1 and note the Location/Region\nSet AZURE_SPEECH_KEY and AZURE_SPEECH_REGION","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"How to Set Up Azure Speech Services","lvl3":""}},
4846
4857
  {"objectID":"07e8bb77fbafe3f5877f90d12e04d98d34a4f9111b78f48572155d30f373fd07","title":"Supported Capabilities","url":"/docs/getting-started/environment-variables#supported-capabilities","content":"TTS: Azure Neural TTS with 400+ voices across 140+ languages\nSTT: Azure Speech-to-Text with real-time and batch transcription","hierarchy":{"lvl0":"Getting Started","lvl1":"🔧 Environment Variables Configuration Guide","lvl2":"Supported Capabilities","lvl3":""}},
@@ -5756,10 +5767,10 @@
5756
5767
  {"objectID":"31a77753d4f34500cc163a9258df22c54d5689c46626d0a064726bba2d6bcb21","title":"Configuration Reference","url":"/docs/getting-started/providers/elevenlabs-music#configuration-reference","content":"| Environment Variable | Required | Description |\n| -------------------- | -------- | -------------- |\n| ELEVENLABS_API_KEY | Yes | ElevenLabs key |","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Music Provider Guide","lvl2":"Configuration Reference","lvl3":""}},
5757
5768
  {"objectID":"dd1135434eb752fb6357da839820c4c52880f5776ae5dc2194586b190d3f8d0b","title":"Troubleshooting","url":"/docs/getting-started/providers/elevenlabs-music#troubleshooting","content":"401 payment_required — your ElevenLabs subscription has an open\n invoice. Complete payment at\n https://elevenlabs.io/app/subscription\n to re-enable the music endpoint.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Music Provider Guide","lvl2":"Troubleshooting","lvl3":""}},
5758
5769
  {"objectID":"35affd3c5e5bdfb145e56d3bdd98804675e82bb625c5fd6322d3abd3b736b007","title":"See Also","url":"/docs/getting-started/providers/elevenlabs-music#see-also","content":"Beatoven Provider\nLyria Provider\nElevenLabs TTS","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Music Provider Guide","lvl2":"See Also","lvl3":""}},
5759
- {"objectID":"4df7f5e2f76e722a5090224b4da09900a612bb4389e80712c86c83cb9d539fc6","title":"ElevenLabs Provider Guide","url":"/docs/getting-started/providers/elevenlabs","content":"ElevenLabs Provider Guide\n\nStudio-quality, multilingual text-to-speech with dynamic voice discovery and voice cloning\n\nOverview\n\nElevenLabs is a specialist voice AI provider known for exceptionally natural-sounding speech synthesis and extensive multilingual support. NeuroLink integrates their TTS API, giving you access to their full voice library — including custom and cloned voices — through the same generate() call used for all other TTS providers.\n\nThe default model, eleven_multilingual_v2, produces high-fidelity audio across 29 languages with a single voice. ElevenLabs voices are dynamically fetched from the API and cached for five minutes, so newly added or cloned voices are always available without restarting your application.\n\nKey Facts\n\n| Property | Value |\n| ----------------- | --------------------------------------------------- |\n| Provider ID | elevenlabs |\n| API endpoint | https://api.elevenlabs.io/v1 |\n| Default model | eleven_multilingual_v2 |\n| Default voice | Rachel (21m00Tcm4TlvDq8ikWAM) |\n| Formats | mp3 (44.1 kHz), wav (PCM 44.1 kHz), ogg (22 kHz) |\n| Max input | 5,000 characters per request |\n| Languages | 29+ languages per voice (auto-detected from input) |\n| Streaming | Not supported in NeuroLink integration (batch only) |\n\nQuick Start\nGet an API Key\n\nSign up at https://elevenlabs.io and copy your API key from Profile → API Key.\nConfigure Environment\n\nAdd to your .env file:\nInstall NeuroLink\nSynthesise Your First Audio\n\nSupported Models\n\n| Model ID | Description | Use Case |\n| ------------------------ | ------------------------------------------------ | --------------------------------- |\n| eleven_multilingual_v2 | Default; 29 languages, highest quality | General use, multilingual content |\n| eleven_monolingual_v1 | English-only, optimised for English naturalness | English-only apps |\n| eleven_multilingual_v1 | First-generation multilingual (superseded by v2) | Legacy compatibility |\n| eleven_turbo_v2 | Fast, lower latency variant | Real-time applications |\n\nPass the model ID explicitly via the ElevenLabsTTSOptions.model field or let the integration default to eleven_multilingual_v2.\n\nSDK Usage\n\nDirect Text Synthesis\n\nSynthesise the input text without calling an AI model:\n\nSpecifying a Voice\n\nVoices are identified by their voice_id string. Use a known ID directly, or list available voices programmatically (see Voice Discovery):\n\nAI Response Synthesis\n\nGenerate a response with an AI model and then synthesise it:\n\nMultilingual Synthesis\n\nElevenLabs detects the language of your input automatically. No extra configuration is needed:\n\nVoice Settings Tuning\n\nFine-tune the voice character using ElevenLabs-specific options:\n\nSave to File\n\nPer-Call Credential Override\n\nCLI Usage\n\nBasic TTS\n\nChoose a Voice\n\nSynthesise AI Response\n\nMultilingual\n\nVoice Discovery\n\nElevenLabs voices are fetched dynamically from your account. The result includes both the ElevenLabs library voices and any custom or cloned voices in your account.\n\nVoices are cached for 5 minutes per handler instance to avoid redundant API calls.\n\nSupported Languages\n\neleven_multilingual_v2 supports 29 languages. The following are recognised by the NeuroLink voice metadata:\n\n| Code | Language |\n| ---- | ---------- |\n| en | English |\n| es | Spanish |\n| fr | French |\n| de | German |\n| it | Italian |\n| pt | Portuguese |\n| pl | Polish |\n| hi | Hindi |\n| ar | Arabic |\n| zh | Chinese |\n| ja | Japanese |\n| ko | Korean |\n\nFor the full language list, refer to the ElevenLabs documentation.\n\nAudio Formats\n\n| Format | Extension | ElevenLabs internal format | Sample Rate |\n| ------ | --------- | -------------------------- | ----------- |\n| mp3 | .mp3 | mp3_44100_128 | 44,100 Hz |\n| wav | .wav | pcm_44100 | 44,100 Hz |\n| ogg | .ogg | ogg_22050 | 22,050 Hz |\n| opus | .opus | ogg_22050 | 22,050 Hz |\n\nConfiguration Reference\n\n| Environment Variable | Required | Default | Description |\n| --------------------- | -------- | ------------------------ | ---------------------- |\n| ELEVENLABS_API_KEY | Yes | — | ElevenLabs API key |\n| ELEVENLABS_VOICE_ID | No | 21m00Tcm4TlvDq8ikWAM | Default voice (Rachel) |\n| ELEVENLABS_MODEL | No | eleven_multilingual_v2 | Default TTS model |\n\nFeature Support Matrix\n\n| Feature | Supported | Notes |\n| ---------------------- | --------- | ------------------------------------------ |\n| Text synthesis | Yes ","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"","lvl3":""}},
5770
+ {"objectID":"4df7f5e2f76e722a5090224b4da09900a612bb4389e80712c86c83cb9d539fc6","title":"ElevenLabs Provider Guide","url":"/docs/getting-started/providers/elevenlabs","content":"ElevenLabs Provider Guide\n\nStudio-quality, multilingual text-to-speech with dynamic voice discovery and voice cloning\n\nOverview\n\nElevenLabs is a specialist voice AI provider known for exceptionally natural-sounding speech synthesis and extensive multilingual support. NeuroLink integrates their TTS API, giving you access to their full voice library — including custom and cloned voices — through the same generate() call used for all other TTS providers.\n\nThe default model, eleven_multilingual_v2, produces high-fidelity audio across 29 languages with a single voice. ElevenLabs voices are dynamically fetched from the API and cached for five minutes, so newly added or cloned voices are always available without restarting your application.\n\nKey Facts\n\n| Property | Value |\n| ----------------- | ------------------------------------------------------------------------ |\n| Provider ID | elevenlabs |\n| API endpoint | https://api.elevenlabs.io/v1 |\n| Default model | eleven_multilingual_v2 |\n| Default voice | Rachel (21m00Tcm4TlvDq8ikWAM) |\n| Formats | mp3 (44.1 kHz), wav (raw PCM 44.1 kHz), ogg/opus (Opus 48 kHz) |\n| Max input | 5,000 characters per request |\n| Languages | 29+ languages per voice (auto-detected from input) |\n| Streaming | Not supported in NeuroLink integration (batch only) |\n| STT | elevenlabs-stt (Scribe) — see Speech-to-Text |\n\nQuick Start\nGet an API Key\n\nSign up at https://elevenlabs.io and copy your API key from Profile → API Key.\nConfigure Environment\n\nAdd to your .env file:\nInstall NeuroLink\nSynthesise Your First Audio\n\nSupported Models\n\n| Model ID | Description | Use Case |\n| ------------------------ | --------------------------------------------------------- | --------------------------------- |\n| eleven_multilingual_v2 | Default; 29 languages, highest quality | General use, multilingual content |\n| eleven_v3 | Most expressive; 70+ languages, accepts language | Narration, dialogue |\n| eleven_flash_v2_5 | Lowest latency (~75 ms), 32 languages, accepts language | Real-time, conversational agents |\n| eleven_flash_v2 | Lowest latency, English only | Real-time English |\n| eleven_turbo_v2_5 | Fast, 32 languages, accepts language | Low-latency multilingual |\n| eleven_turbo_v2 | Fast, lower latency variant, English | Real-time applications |\n| eleven_monolingual_v1 | English-only, optimised for English naturalness | English-only apps |\n\nPass the model ID explicitly via the ElevenLabsTTSOptions.model field or let the integration default to eleven_multilingual_v2.\n\nLanguage pinning. Set tts.language (generic) or tts.languageCode\n(ElevenLabs-specific) to pin the language; a BCP-47 tag such as en-US is\nreduced to en. The code is sent on every model except\neleven_multilingual_v2, the one model the API rejects it on — there it is\nlogged and dropped, and the model auto-detects the language from the text.\nModels that do not use the field (eleven_flash_v2, eleven_turbo_v2,\neleven_monolingual_v1) ignore it server-side rather than failing.\n\nSDK Usage\n\nDirect Text Synthesis\n\nSynthesise the input text without calling an AI model:\n\nSpecifying a Voice\n\nVoices are identified by their voice_id string. Use a known ID directly, or list available voices programmatically (see Voice Discovery):\n\nAI Response Synthesis\n\nGenerate a response with an AI model and then synthesise it:\n\nMultilingual Synthesis\n\nElevenLabs detects the language of your input automatically. No extra configuration is needed:\n\nVoice Settings Tuning\n\nFine-tune the voice character using ElevenLabs-specific options:\n\nspeed is the generic TTSOptions.speed (0.25–4.0). ElevenLabs accepts only\n0.7–1.2, so out-of-range values are clamped into that band — with a\nlogger.warn — rather than rejected.\n\nBitrates, timeouts and retries\n\nA request is retried on 429, any 5xx, a per-attempt timeout or a\ntransport error (a refused or reset connection, a DNS failure), honouring\nRetry-After when the response carries one (capped at 10 s) and backing off\nexponentially from 500 ms otherwise. A 4xx other than 429 fails\nimmediately and is marked non-retriable, as does anything thrown before a\nrequest exists (a malformed baseUrl). generate()'s own synthesis timeout\nis raised to at least timeoutMs × (1 + retries) plus pause slack — using\nthe defaults above (30 s, one retry) for any knob you leave unset —","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"","lvl3":""}},
5760
5771
  {"objectID":"a129ca5bb9d9660d84434ece876f36588b678b1666ee6cbbec64249ed4693d40","title":"ElevenLabs Provider Guide","url":"/docs/getting-started/providers/elevenlabs#elevenlabs-provider-guide","content":"Studio-quality, multilingual text-to-speech with dynamic voice discovery and voice cloning","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"ElevenLabs Provider Guide","lvl3":""}},
5761
5772
  {"objectID":"24ff2fbe48fc82b409cf5e6d54526bf1ea1e32096a5fee1e070cc6f9bdf670b5","title":"Overview","url":"/docs/getting-started/providers/elevenlabs#overview","content":"ElevenLabs is a specialist voice AI provider known for exceptionally natural-sounding speech synthesis and extensive multilingual support. NeuroLink integrates their TTS API, giving you access to their full voice library — including custom and cloned voices — through the same generate() call used for all other TTS providers.\n\nThe default model, eleven_multilingual_v2, produces high-fidelity audio across 29 languages with a single voice. ElevenLabs voices are dynamically fetched from the API and cached for five minutes, so newly added or cloned voices are always available without restarting your application.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Overview","lvl3":""}},
5762
- {"objectID":"41d89e83dea2f2beb29d78ee9b296879eef6d925b412ffaf4da86e3cf29daedc","title":"Key Facts","url":"/docs/getting-started/providers/elevenlabs#key-facts","content":"| Property | Value |\n| ----------------- | --------------------------------------------------- |\n| Provider ID | elevenlabs |\n| API endpoint | https://api.elevenlabs.io/v1 |\n| Default model | eleven_multilingual_v2 |\n| Default voice | Rachel (21m00Tcm4TlvDq8ikWAM) |\n| Formats | mp3 (44.1 kHz), wav (PCM 44.1 kHz), ogg (22 kHz) |\n| Max input | 5,000 characters per request |\n| Languages | 29+ languages per voice (auto-detected from input) |\n| Streaming | Not supported in NeuroLink integration (batch only) |","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Key Facts","lvl3":""}},
5773
+ {"objectID":"41d89e83dea2f2beb29d78ee9b296879eef6d925b412ffaf4da86e3cf29daedc","title":"Key Facts","url":"/docs/getting-started/providers/elevenlabs#key-facts","content":"| Property | Value |\n| ----------------- | ------------------------------------------------------------------------ |\n| Provider ID | elevenlabs |\n| API endpoint | https://api.elevenlabs.io/v1 |\n| Default model | eleven_multilingual_v2 |\n| Default voice | Rachel (21m00Tcm4TlvDq8ikWAM) |\n| Formats | mp3 (44.1 kHz), wav (raw PCM 44.1 kHz), ogg/opus (Opus 48 kHz) |\n| Max input | 5,000 characters per request |\n| Languages | 29+ languages per voice (auto-detected from input) |\n| Streaming | Not supported in NeuroLink integration (batch only) |\n| STT | elevenlabs-stt (Scribe) — see Speech-to-Text |","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Key Facts","lvl3":""}},
5763
5774
  {"objectID":"d1c99d23a944ba8d78b91ad336038f39524a4c5e8363d288db922c8d03f82ef3","title":"1. Get an API Key","url":"/docs/getting-started/providers/elevenlabs#1-get-an-api-key","content":"Sign up at https://elevenlabs.io and copy your API key from Profile → API Key.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"1. Get an API Key","lvl3":""}},
5764
5775
  {"objectID":"3193681bb86e77279344e2e476f724dcba2745875f0a20f791967a06dfc42eca","title":"2. Configure Environment","url":"/docs/getting-started/providers/elevenlabs#2-configure-environment","content":"Add to your .env file:\n\n`bash","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"2. Configure Environment","lvl3":""}},
5765
5776
  {"objectID":"eeac876539b94922c431793478cf8135375346a2b1efdb2cc6e544d8f9190d45","title":"Required","url":"/docs/getting-started/providers/elevenlabs#required","content":"ELEVENLABSAPIKEY=your-api-key-here","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Required","lvl3":""}},
@@ -5767,25 +5778,28 @@
5767
5778
  {"objectID":"95af7fbdc01f27eaa7ed715a499eb357d45ee3957f28a9744369cf67b605c4ea","title":"Optional: default model (default: eleven_multilingual_v2)","url":"/docs/getting-started/providers/elevenlabs#optional-default-model-default-eleven_multilingual_v2","content":"ELEVENLABSMODEL=elevenmultilingual_v2\n`","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Optional: default model (default: eleven_multilingual_v2)","lvl3":""}},
5768
5779
  {"objectID":"b57af40aa8ee331509b0b93403774596618da5ec0fc39e9698c25dca31c6a4c7","title":"3. Install NeuroLink","url":"/docs/getting-started/providers/elevenlabs#3-install-neurolink","content":"`bash\nnpm install @juspay/neurolink","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"3. Install NeuroLink","lvl3":""}},
5769
5780
  {"objectID":"9494bae3f29673d4672896a88fd677a3fd98a02e4a37be39fca7fa5664acd659","title":"or","url":"/docs/getting-started/providers/elevenlabs#or","content":"pnpm add @juspay/neurolink\n`","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"or","lvl3":""}},
5770
- {"objectID":"327b038fe13531b6ecbe8480b393107be39ad4fe1bd71e41db85da95ac601ff5","title":"Supported Models","url":"/docs/getting-started/providers/elevenlabs#supported-models","content":"| Model ID | Description | Use Case |\n| ------------------------ | ------------------------------------------------ | --------------------------------- |\n| eleven_multilingual_v2 | Default; 29 languages, highest quality | General use, multilingual content |\n| eleven_monolingual_v1 | English-only, optimised for English naturalness | English-only apps |\n| eleven_multilingual_v1 | First-generation multilingual (superseded by v2) | Legacy compatibility |\n| eleven_turbo_v2 | Fast, lower latency variant | Real-time applications |\n\nPass the model ID explicitly via the ElevenLabsTTSOptions.model field or let the integration default to eleven_multilingual_v2.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Supported Models","lvl3":""}},
5781
+ {"objectID":"327b038fe13531b6ecbe8480b393107be39ad4fe1bd71e41db85da95ac601ff5","title":"Supported Models","url":"/docs/getting-started/providers/elevenlabs#supported-models","content":"| Model ID | Description | Use Case |\n| ------------------------ | --------------------------------------------------------- | --------------------------------- |\n| eleven_multilingual_v2 | Default; 29 languages, highest quality | General use, multilingual content |\n| eleven_v3 | Most expressive; 70+ languages, accepts language | Narration, dialogue |\n| eleven_flash_v2_5 | Lowest latency (~75 ms), 32 languages, accepts language | Real-time, conversational agents |\n| eleven_flash_v2 | Lowest latency, English only | Real-time English |\n| eleven_turbo_v2_5 | Fast, 32 languages, accepts language | Low-latency multilingual |\n| eleven_turbo_v2 | Fast, lower latency variant, English | Real-time applications |\n| eleven_monolingual_v1 | English-only, optimised for English naturalness | English-only apps |\n\nPass the model ID explicitly via the ElevenLabsTTSOptions.model field or let the integration default to eleven_multilingual_v2.\n\nLanguage pinning. Set tts.language (generic) or tts.languageCode\n(ElevenLabs-specific) to pin the language; a BCP-47 tag such as en-US is\nreduced to en. The code is sent on every model except\neleven_multilingual_v2, the one model the API rejects it on — there it is\nlogged and dropped, and the model auto-detects the language from the text.\nModels that do not use the field (eleven_flash_v2, eleven_turbo_v2,\neleven_monolingual_v1) ignore it server-side rather than failing.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Supported Models","lvl3":""}},
5771
5782
  {"objectID":"2b1beef138947956d545298b487ebeca94565c2910e2f753838b554aa0e4613d","title":"Direct Text Synthesis","url":"/docs/getting-started/providers/elevenlabs#direct-text-synthesis","content":"Synthesise the input text without calling an AI model:","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Direct Text Synthesis","lvl3":""}},
5772
5783
  {"objectID":"d0faac05111253b91fcc32d5e193d9d914888d31162c30583258ad488b71fd10","title":"Specifying a Voice","url":"/docs/getting-started/providers/elevenlabs#specifying-a-voice","content":"Voices are identified by their voice_id string. Use a known ID directly, or list available voices programmatically (see Voice Discovery):","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Specifying a Voice","lvl3":""}},
5773
5784
  {"objectID":"53de94f57b4316be874de4225d2cf1bbb910f33e65d42041f59586eea2a54cf0","title":"AI Response Synthesis","url":"/docs/getting-started/providers/elevenlabs#ai-response-synthesis","content":"Generate a response with an AI model and then synthesise it:","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"AI Response Synthesis","lvl3":""}},
5774
5785
  {"objectID":"42a8342ec438a87ab0cb36d7013305fedda2dac9addb545d0ecfbe64e39731a0","title":"Multilingual Synthesis","url":"/docs/getting-started/providers/elevenlabs#multilingual-synthesis","content":"ElevenLabs detects the language of your input automatically. No extra configuration is needed:","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Multilingual Synthesis","lvl3":""}},
5775
- {"objectID":"48e57deedaa4bcd00d2cfde2b2e1f6f280b8f07b72cff2cf3187ff09b05b0d7e","title":"Voice Settings Tuning","url":"/docs/getting-started/providers/elevenlabs#voice-settings-tuning","content":"Fine-tune the voice character using ElevenLabs-specific options:","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Voice Settings Tuning","lvl3":""}},
5786
+ {"objectID":"48e57deedaa4bcd00d2cfde2b2e1f6f280b8f07b72cff2cf3187ff09b05b0d7e","title":"Voice Settings Tuning","url":"/docs/getting-started/providers/elevenlabs#voice-settings-tuning","content":"Fine-tune the voice character using ElevenLabs-specific options:\n\nspeed is the generic TTSOptions.speed (0.25–4.0). ElevenLabs accepts only\n0.7–1.2, so out-of-range values are clamped into that band — with a\nlogger.warn — rather than rejected.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Voice Settings Tuning","lvl3":""}},
5787
+ {"objectID":"57d0f6753039ac23349820d3c707dbe18598e45afe908fa7a35dc5771c6f8940","title":"Bitrates, timeouts and retries","url":"/docs/getting-started/providers/elevenlabs#bitrates-timeouts-and-retries","content":"A request is retried on 429, any 5xx, a per-attempt timeout or a\ntransport error (a refused or reset connection, a DNS failure), honouring\nRetry-After when the response carries one (capped at 10 s) and backing off\nexponentially from 500 ms otherwise. A 4xx other than 429 fails\nimmediately and is marked non-retriable, as does anything thrown before a\nrequest exists (a malformed baseUrl). generate()'s own synthesis timeout\nis raised to at least timeoutMs × (1 + retries) plus pause slack — using\nthe defaults above (30 s, one retry) for any knob you leave unset — so the\nhandler's retry loop is never cut short from outside, including on a default\ncall. To stop early, pass an abortSignal to generate() (or signal on the\nTTS options when calling the handler directly): the attempt in flight is\naborted and no further attempt is made. timeoutMs is capped at 2³¹−1 ms,\nthe largest delay a timer honours. An mp3Bitrate / opusBitrate outside\nthe listed values falls back to the default with a warning rather than being\nsent.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Bitrates, timeouts and retries","lvl3":""}},
5776
5788
  {"objectID":"f67eb9a0d733e0ea83973083e936b81615edfdccac4cbbdf1c6e08d8cdd11ae2","title":"Basic TTS","url":"/docs/getting-started/providers/elevenlabs#basic-tts","content":"`bash","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Basic TTS","lvl3":""}},
5777
5789
  {"objectID":"6f48a00492227027df36f9072380ecbecacac8bb49d05970075895c77b75a3eb","title":"Synthesise text using ElevenLabs","url":"/docs/getting-started/providers/elevenlabs#synthesise-text-using-elevenlabs","content":"neurolink generate \"Hello from ElevenLabs!\" --tts --tts-provider elevenlabs","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Synthesise text using ElevenLabs","lvl3":""}},
5778
5790
  {"objectID":"7ee32463b67da776f9d9fd08edf47c8d3c6258a43752a4b9313b0c529c49b74f","title":"Save to file","url":"/docs/getting-started/providers/elevenlabs#save-to-file-1","content":"neurolink generate \"Saving to disk.\" \\\n --tts --tts-provider elevenlabs \\\n --tts-output output.mp3\n`","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Save to file","lvl3":""}},
5779
5791
  {"objectID":"2d687c476721a4721e9de2e85de8f1b6b160862474feb81e387b93bfdec0ced9","title":"Voice Discovery","url":"/docs/getting-started/providers/elevenlabs#voice-discovery","content":"ElevenLabs voices are fetched dynamically from your account. The result includes both the ElevenLabs library voices and any custom or cloned voices in your account.\n\nVoices are cached for 5 minutes per handler instance to avoid redundant API calls.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Voice Discovery","lvl3":""}},
5780
5792
  {"objectID":"378ce2c5e57f8bfbcf4330eb4d4a7a0d94a6364e6c18d8f7e8d2c237732c6ca1","title":"Supported Languages","url":"/docs/getting-started/providers/elevenlabs#supported-languages","content":"eleven_multilingual_v2 supports 29 languages. The following are recognised by the NeuroLink voice metadata:\n\n| Code | Language |\n| ---- | ---------- |\n| en | English |\n| es | Spanish |\n| fr | French |\n| de | German |\n| it | Italian |\n| pt | Portuguese |\n| pl | Polish |\n| hi | Hindi |\n| ar | Arabic |\n| zh | Chinese |\n| ja | Japanese |\n| ko | Korean |\n\nFor the full language list, refer to the ElevenLabs documentation.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Supported Languages","lvl3":""}},
5781
- {"objectID":"98898ee9e8ccb1a9a4f72ce734d2a6110c935b8877fde2bc126a4770e6269cbf","title":"Audio Formats","url":"/docs/getting-started/providers/elevenlabs#audio-formats","content":"| Format | Extension | ElevenLabs internal format | Sample Rate |\n| ------ | --------- | -------------------------- | ----------- |\n| mp3 | .mp3 | mp3_44100_128 | 44,100 Hz |\n| wav | .wav | pcm_44100 | 44,100 Hz |\n| ogg | .ogg | ogg_22050 | 22,050 Hz |\n| opus | .opus | ogg_22050 | 22,050 Hz |","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Audio Formats","lvl3":""}},
5782
- {"objectID":"8d23e3b9642b34aeb1cd9d30dc235cff9fab0a5fe0e06e0aa8b1acdaf72e23b6","title":"Configuration Reference","url":"/docs/getting-started/providers/elevenlabs#configuration-reference","content":"| Environment Variable | Required | Default | Description |\n| --------------------- | -------- | ------------------------ | ---------------------- |\n| ELEVENLABS_API_KEY | Yes | — | ElevenLabs API key |\n| ELEVENLABS_VOICE_ID | No | 21m00Tcm4TlvDq8ikWAM | Default voice (Rachel) |\n| ELEVENLABS_MODEL | No | eleven_multilingual_v2 | Default TTS model |","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Configuration Reference","lvl3":""}},
5783
- {"objectID":"2ae54196a2149b420a576c98c6392982b9034b308e685a082f479a01a315083f","title":"Feature Support Matrix","url":"/docs/getting-started/providers/elevenlabs#feature-support-matrix","content":"| Feature | Supported | Notes |\n| ---------------------- | --------- | ------------------------------------------ |\n| Text synthesis | Yes | |\n| AI response synthesis | Yes | Set useAiResponse: true |\n| Multilingual support | Yes | 29 languages, auto-detected |\n| Voice discovery | Yes | Dynamic API fetch, 5-minute cache |\n| Custom / cloned voices | Yes | Pass voice ID from your ElevenLabs account |\n| Voice stability tuning | Yes | stability, similarityBoost, style |\n| Multiple formats | Yes | mp3, wav, ogg, opus |\n| Streaming TTS | No | Batch synthesis only in NeuroLink |\n| Speed control | No | Not supported by this integration |","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Feature Support Matrix","lvl3":""}},
5793
+ {"objectID":"98898ee9e8ccb1a9a4f72ce734d2a6110c935b8877fde2bc126a4770e6269cbf","title":"Audio Formats","url":"/docs/getting-started/providers/elevenlabs#audio-formats","content":"| Format | Extension | ElevenLabs output_format | Sample Rate | audio.format |\n| ------ | --------- | -------------------------------- | ----------- | -------------- |\n| mp3 | .mp3 | mp3_44100_<mp3Bitrate> (128) | 44,100 Hz | mp3 |\n| wav | .wav | pcm_44100 — raw PCM, no header | 44,100 Hz | pcm16 |\n| ogg | .ogg | opus_48000_<opusBitrate> (64) | 48,000 Hz | opus |\n| opus | .opus | opus_48000_<opusBitrate> (64) | 48,000 Hz | opus |\n\nElevenLabs has no ogg_* output family — Ogg/Opus is opus_48000_<kbps>.\nEarlier NeuroLink releases sent ogg_22050 for ogg/opus, which the API\nrejects with a 422; that is fixed. The returned Ogg container starts with the\nOggS page marker and an OpusHead packet. wav output is headerless\nPCM (reported as pcm16): wrap it with createWavFile() from\n@juspay/neurolink/voice before writing a .wav file, and pass the sample\nrate — createWavFile defaults to 16 kHz, while ElevenLabs PCM is 44.1 kHz,\nso a header written with the default plays 2.76× slow and low:","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Audio Formats","lvl3":""}},
5794
+ {"objectID":"8d23e3b9642b34aeb1cd9d30dc235cff9fab0a5fe0e06e0aa8b1acdaf72e23b6","title":"Configuration Reference","url":"/docs/getting-started/providers/elevenlabs#configuration-reference","content":"| Environment Variable | Required | Default | Description |\n| --------------------- | -------- | ------------------------------ | ----------------------------------------------- |\n| ELEVENLABS_API_KEY | Yes | — | ElevenLabs API key (shared by TTS, STT, music) |\n| ELEVENLABS_BASE_URL | No | https://api.elevenlabs.io/v1 | API base URL including /v1 (proxies, tests) |\n| ELEVENLABS_VOICE_ID | No | 21m00Tcm4TlvDq8ikWAM | Default voice (Rachel); a per-call voice wins |\n| ELEVENLABS_MODEL | No | eleven_multilingual_v2 | Default TTS model; a per-call model wins |","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Configuration Reference","lvl3":""}},
5795
+ {"objectID":"2ae54196a2149b420a576c98c6392982b9034b308e685a082f479a01a315083f","title":"Feature Support Matrix","url":"/docs/getting-started/providers/elevenlabs#feature-support-matrix","content":"| Feature | Supported | Notes |\n| ---------------------- | --------- | ------------------------------------------------------------------- |\n| Text synthesis | Yes | |\n| AI response synthesis | Yes | Set mode: \"response\" |\n| Multilingual support | Yes | 29 languages, auto-detected |\n| Language pinning | Yes | language (ISO 639-1; en-US → en) on all but multilingual_v2 |\n| Voice discovery | Yes | Dynamic API fetch, 5-minute cache |\n| Custom / cloned voices | Yes | Pass voice ID from your ElevenLabs account |\n| Voice stability tuning | Yes | stability, similarityBoost, style, voiceSettings |\n| Multiple formats | Yes | mp3 (bitrate), raw pcm, opus 48 kHz (bitrate) |\n| Streaming TTS | No | Batch synthesis only in NeuroLink |\n| Speed control | Yes | speed, clamped to 0.7–1.2 |\n| Retries | Yes | retries (default 1) on 429/5xx/timeout, honours Retry-After |\n| Speech-to-text | Yes | elevenlabs-stt (Scribe), aliases scribe, elevenlabs |","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Feature Support Matrix","lvl3":""}},
5796
+ {"objectID":"7bab2aa9a7960737443c19f3980611cb1c6210e53adc709ac61135cf4ee4ffb7","title":"Speech-to-Text (Scribe)","url":"/docs/getting-started/providers/elevenlabs#speech-to-text-scribe","content":"The same key also unlocks ElevenLabs Scribe for batch transcription. The STT\nhandler is registered as elevenlabs-stt, with scribe and elevenlabs as\naliases — the STT and TTS registries are separate, so\nstt: { provider: \"elevenlabs\" } and tts: { provider: \"elevenlabs\" }\nresolve to different handlers.\n\nRequest shape: POST {baseUrl}/speech-to-text, header xi-api-key,\nmultipart fields file, model_id (default scribe_v2; scribe_v1 is\ndeprecated by ElevenLabs and any newer id can be passed as a string),\nlanguage_code (only when you set language; a BCP-47 tag like en-US is\nreduced to en), tag_audio_events (false unless tagAudioEvents: true),\ndiarize, num_speakers. Spacing and audio-event entries in Scribe's\nwords[] are dropped from transcription.words; speaker_id becomes\nspeaker. transcription.confidence is the mean per-word exp(logprob)\nover the spoken words when Scribe reports one; when no word carries a\nlogprob it falls back to language_probability, and to 0 when that is\nmissing too. transcription.metadata.confidenceSource says which it was —\n\"word_logprobs\", \"language_probability\" or \"none\" — because Scribe's\nlanguage_probability measures how sure it is of the language, not the\nwords (garbled and clean audio both score ~0.99), and it is always exposed\nunder its own name as transcription.metadata.languageProbability. timeoutMs (default 60 000, covering the response body as\nwell as the headers) and baseUrl are accepted on the same options. Scribe\nis batch-only: supportsStreaming is false and there is no\ntranscribeStream.\n\nCLI (--stt is a flag; the file goes in --input-audio):","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Speech-to-Text (Scribe)","lvl3":""}},
5784
5797
  {"objectID":"e04424fe1fdfc411774ab9519e5abaa3252946011a29e23bdada34aa6ff4278c","title":"\"ElevenLabs API key not configured\"","url":"/docs/getting-started/providers/elevenlabs#elevenlabs-api-key-not-configured","content":"The ELEVENLABS_API_KEY environment variable is missing or was not loaded.\n\nRetrieve your key from https://elevenlabs.io/app/settings/api-keys.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"\"ElevenLabs API key not configured\"","lvl3":""}},
5785
5798
  {"objectID":"2e588cd3d603f2417c1c352588cc4ec823ba1b5bb70d8b8a743616e090d2efd0","title":"\"HTTP 401\" — Unauthorised","url":"/docs/getting-started/providers/elevenlabs#http-401-unauthorised","content":"Your API key is invalid or has been revoked. Generate a new key from the ElevenLabs dashboard.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"\"HTTP 401\" — Unauthorised","lvl3":""}},
5786
5799
  {"objectID":"29df39f51d560e23bb6c52a4b10e776c9e594d523ffc9cf1b7939759f9175ba0","title":"\"HTTP 429\" — Rate limit or quota exceeded","url":"/docs/getting-started/providers/elevenlabs#http-429-rate-limit-or-quota-exceeded","content":"You have reached your character quota for the billing period, or exceeded the per-minute request rate. Check your usage at https://elevenlabs.io/app/subscription.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"\"HTTP 429\" — Rate limit or quota exceeded","lvl3":""}},
5787
5800
  {"objectID":"f5bec76ffa394d5a95be9620238f3a730a0ff0be2f1a523e03bd71bf75cde6a9","title":"\"HTTP 400\" — Request too long","url":"/docs/getting-started/providers/elevenlabs#http-400-request-too-long","content":"The input text exceeds 5,000 characters. Split the content into chunks:","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"\"HTTP 400\" — Request too long","lvl3":""}},
5788
- {"objectID":"3370cad93f77c2272239ca3f3b8ace39bfec46cb1a0e07e33ee57c5f69753fae","title":"\"ElevenLabs TTS request timed out after 30 seconds\"","url":"/docs/getting-started/providers/elevenlabs#elevenlabs-tts-request-timed-out-after-30-seconds","content":"A slow network or high server load caused the request to time out. This error is marked retriable — retry with backoff.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"\"ElevenLabs TTS request timed out after 30 seconds\"","lvl3":""}},
5801
+ {"objectID":"374b12df029021a97619ce31a57565a57e9d54c21705dcdc09220ce5b2665d63","title":"\"ElevenLabs TTS request timed out after 30000ms\"","url":"/docs/getting-started/providers/elevenlabs#elevenlabs-tts-request-timed-out-after-30000ms","content":"A slow network or high server load caused one attempt to time out. The\nhandler already retries once by default (retries); raise timeoutMs for\nvery long inputs, or retries for a flaky network.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"\"ElevenLabs TTS request timed out after 30000ms\"","lvl3":""}},
5802
+ {"objectID":"682d0be20594b8999ba1cd626403c8b2c67ae0bc205bd5836d601212650ef373","title":"\"HTTP 422\" on format: \"ogg\" / \"opus\"","url":"/docs/getting-started/providers/elevenlabs#http-422-on-format-ogg-opus","content":"Fixed: earlier releases asked ElevenLabs for ogg_22050, which is not one of\nits output formats. ogg/opus now request opus_48000_<opusBitrate>.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"\"HTTP 422\" on format: \"ogg\" / \"opus\"","lvl3":""}},
5789
5803
  {"objectID":"293d0cf78c8b91321aaea4539752c75c5d23b0f630e75d8c039fa5b10759fbd8","title":"Voice not found","url":"/docs/getting-started/providers/elevenlabs#voice-not-found","content":"You passed a voice ID that does not exist in your account. List available voices to confirm:","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"Voice not found","lvl3":""}},
5790
5804
  {"objectID":"a8f667c71e278a2fbdf507c9d16d18418a74fc97ae593129deaa675058c728f5","title":"\"Failed to get voices\"","url":"/docs/getting-started/providers/elevenlabs#failed-to-get-voices","content":"Voice discovery failed (network error or invalid key). The 5-minute cache shields against transient failures, but a hard failure at startup will propagate. Ensure ELEVENLABS_API_KEY is valid and the ElevenLabs API is reachable.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"\"Failed to get voices\"","lvl3":""}},
5791
5805
  {"objectID":"58ee78d9a6be3099cc23a438c6255e483cabb54fdd59e63c6d9de2a3e10068ad","title":"See Also","url":"/docs/getting-started/providers/elevenlabs#see-also","content":"TTS Integration Guide — complete multi-provider TTS reference\nOpenAI TTS Provider Guide — alternative TTS provider\nAudio Input (STT) — speech-to-text counterpart\nVoice Agent Guide — building full voice assistants\n\nNeed Help? Join the GitHub Discussions or open an issue.","hierarchy":{"lvl0":"Getting Started","lvl1":"ElevenLabs Provider Guide","lvl2":"See Also","lvl3":""}},
@@ -9386,14 +9400,14 @@
9386
9400
  {"objectID":"19a5d28f96d3426d2641ee34600e3973d0bd852b5cb94496c5ee244a445d3d64","title":"Security review","url":"/docs/provider-integration/13-code-review#security-review","content":"✅ API keys read from env vars (DEEPSEEK_API_KEY, NVIDIA_NIM_API_KEY)\n✅ LM_STUDIO_BASE_URL and LLAMACPP_BASE_URL default to localhost; not auto-exposed\n✅ makeLoggingFetch truncates request bodies to 600 chars and response bodies to 400 chars in logs (limits leak of large payloads)\n✅ No hardcoded credentials in tests\n✅ Per-call credentials honored (per NeurolinkCredentials slice)\n\n✅ Note: makeLoggingFetch writes request/response body excerpts to stderr only on non-2xx responses and only when NEUROLINK_DEBUG_HTTP=1 is set. Default behavior logs status/url/reqSize only — no body capture — so user prompts to paid providers (DeepSeek/NIM) cannot leak to stderr in production unless an operator opts in.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Self Code Review (agent rate-limited; reviewed manually)","lvl2":"Security review","lvl3":""}},
9387
9401
  {"objectID":"66d21e6288d5d2a6741ab7b363f01335e355da2d9dbb8b8d231b1be5d24b2e76","title":"Backward compatibility","url":"/docs/provider-integration/13-code-review#backward-compatibility","content":"✅ No breaking changes to public SDK API. Existing callers still work.\n✅ pricing.ts _default change: only adds a NEW fallback step at the end of the chain. Existing providers that don't have _default are unaffected (their lookup behavior is identical).\n✅ AIProviderName enum extended (additive). Existing values unchanged.\n✅ NeurolinkCredentials extended (additive).\n✅ Tests modified are test-only files; not shipped in npm package.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Self Code Review (agent rate-limited; reviewed manually)","lvl2":"Backward compatibility","lvl3":""}},
9388
9402
  {"objectID":"8d090a8ca59a818274009f8c90380e79ef1eb8cafb571a385ba9646d0a86790f","title":"Final recommendation","url":"/docs/provider-integration/13-code-review#final-recommendation","content":"✅ Approve. MED-1 (mutable BaseProvider.modelName + refreshHandlersForModel) is shipped; MED-2 (getOutputReserve clamp) was attempted and reverted in favor of the per-suite … || 1024 test-fallback fix — see the entries above. Optional polish before merge:\nReorder imports/helpers in 4 provider files (LOW-1)\nUpdate 10-test-results-final.md to remove dead test-results-v\\* references (LOW-4)","hierarchy":{"lvl0":"Provider Integration","lvl1":"Self Code Review (agent rate-limited; reviewed manually)","lvl2":"Final recommendation","lvl3":""}},
9389
- {"objectID":"ae30723fc794669f92c1f23a72705db4a35e0ff224d11e71efdc1654bf83a6db","title":"14 · Voice / Speech Integration — Implementation Journal","url":"/docs/provider-integration/14-voice-speech-integration","content":"14 · Voice / Speech Integration — Implementation Journal\n\nCommit: 27a31c32 — feat(voice): add multi-provider TTS, STT, and realtime voice integration\n\nArchitecture\n\nHow voice plugs into Factory + Registry\n\nThe voice integration does not add AI providers (it adds no entries to AIProviderName). Instead it introduces three parallel static registries that mirror the ProviderFactory / ProviderRegistry pattern for non-LLM capabilities:\n\nEach processor exposes registerHandler(name, handler) and the appropriate operation (synthesize, transcribe, connect). The same O(1) Map lookup and lazy-instantiation pattern used by ProviderRegistry applies here.\n\nRegistration location\n\nAll handler registration happens at the bottom of ProviderRegistry.registerAllProviders() in src/lib/factories/providerRegistry.ts, after all LLM providers are registered. The order is:\nLLM providers (existing)\nTTS handler registration block\nSTT handler registration block\nRealtime handler registration block\n\nEach block uses a separate try/catch so a missing API key or a broken import cannot prevent the LLM providers from registering. Registration is fire-and-forget: failures log a warn and continue.\n\nAll imports inside the registration blocks are dynamic (await import(...)), matching CLAUDE.md rule #1 and preventing circular dependencies.\n\nSTT preprocessing in neurolink.ts runStandardGenerateRequest()\n\nWhen a caller passes { stt: { enabled: true, audio: buffer } } to generate(), the following happens inside runStandardGenerateRequest() before the LLM call:\nProviderRegistry.isRegistered() is checked; if false, registerAllProviders() is awaited.\nSTTProcessor is dynamically imported and transcribe(audio, providerName, sttOptions) is called.\nThe transcription text is injected into the LLM prompt:\nIf no user text exists, the transcription becomes the prompt directly.\nIf user text exists, the transcription is prepended as [Transcribed audio]: <text>\\n\\n<user text>.\ngenerateResult.transcription is set to the STTResult object (available to callers).\nFailure-handling — split by whether the caller provided text:\nAudio-only requests (stt.audio present, no user text) — transcription failures fail fast: STTError propagates and generate() rejects, since there is no fallback prompt.\nText + audio requests — transcription failures are logged via logger.error and generate() continues with the un-augmented user text (preserves the optional-augmentation contract).\n\nType organisation\n\nThree new canonical type files added to src/lib/types/ (CLAUDE.md rule #8 compliant — no \"Types\" suffix):\n\n| File | Contents |\n| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| src/lib/types/tts.ts | Extended AudioFormat (added m4a, flac, webm, mp4, mpeg, mpga); added TTSOptions.provider field |\n| src/lib/types/stt.ts | STTHandler, STTOptions, STTResult, STTLanguage, WordTiming, TranscriptionSegment, STT_ERROR_CODES, DEFAULT_STT_OPTIONS, guards |\n| src/lib/types/realtime.ts | RealtimeHandler, RealtimeConfig, RealtimeSession, RealtimeAudioChunk, RealtimeSessionState, REALTIME_ERROR_CODES, DEFAULT_REALTIME_CONFIG |\n| src/lib/types/voice.ts | Aggregator: re-exports all of tts.ts, stt.ts, realtime.ts; adds VoiceCapability, VoiceProviderName, VoiceProviderConfig, VoiceErrorOptions |\n\nsrc/lib/types/index.ts gets two new export * lines (for stt.ts and realtime.ts; voice.ts is already present). All rules 9 and 10 apply: type names are globally unique, barrel uses export * only.\n\nTTS Providers Added\n\nopenai-tts\nFile: src/lib/voice/providers/OpenAITTS.ts (253 lines, NEW)\nClass: OpenAITTS implements TTSHandler\nAPI: POST https://api.openai.com/v1/audio/speech\nAuth: Authorization: Bearer $OPENAI_API_KEY\nModels: tts-1 (standard, default) and tts-1-hd (high quality; selected when options.quality === \"hd\")\nVoices (6): alloy, echo, fable, onyx, nova, shimmer\nOutput formats: mp3 (default), wav, opus/ogg (mapped to OpenAI's opus)\nMax text: 4 096 characters\nRegistered as: \"openai-tts\" in TTSProcessor\nTimeout: 30-second AbortController on every fetch call; throws TTSError with TTS_ERROR_CODES.SYNTHESIS_FAILED on abort\n\nelevenlabs\nFile: src/lib/voice/providers/ElevenLabsTTS.ts (326 lines, NEW)\nClass: ElevenLabsTTS implements TTSHandler\nAPI: POST https://api.elevenlabs.io/v1/text-to-speech/{voice_id}?output_format=...\nAuth: xi-api-key: $ELEVENLABS_API_KEY\nModel: eleven_multilingual_v2 (default)\nVoices: Dynamic — fetched from /v1/voices and cached for 5 minutes. Default voice: 21m00Tcm4TlvDq8ikWAM (Rachel).\nOutput formats: mp3_44100_128 (mp3), pcm_44100 (wav), ogg_22050 (ogg/opus)\nVoice settings: stability (default 0.5), similarity_boost (0.75), ","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"","lvl3":""}},
9403
+ {"objectID":"ae30723fc794669f92c1f23a72705db4a35e0ff224d11e71efdc1654bf83a6db","title":"14 · Voice / Speech Integration — Implementation Journal","url":"/docs/provider-integration/14-voice-speech-integration","content":"14 · Voice / Speech Integration — Implementation Journal\n\nCommit: 27a31c32 — feat(voice): add multi-provider TTS, STT, and realtime voice integration\n\nArchitecture\n\nHow voice plugs into Factory + Registry\n\nThe voice integration does not add AI providers (it adds no entries to AIProviderName). Instead it introduces three parallel static registries that mirror the ProviderFactory / ProviderRegistry pattern for non-LLM capabilities:\n\nEach processor exposes registerHandler(name, handler) and the appropriate operation (synthesize, transcribe, connect). The same O(1) Map lookup and lazy-instantiation pattern used by ProviderRegistry applies here.\n\nRegistration location\n\nAll handler registration happens at the bottom of ProviderRegistry.registerAllProviders() in src/lib/factories/providerRegistry.ts, after all LLM providers are registered. The order is:\nLLM providers (existing)\nTTS handler registration block\nSTT handler registration block\nRealtime handler registration block\n\nEach block uses a separate try/catch so a missing API key or a broken import cannot prevent the LLM providers from registering. Registration is fire-and-forget: failures log a warn and continue.\n\nAll imports inside the registration blocks are dynamic (await import(...)), matching CLAUDE.md rule #1 and preventing circular dependencies.\n\nSTT preprocessing in neurolink.ts runStandardGenerateRequest()\n\nWhen a caller passes { stt: { enabled: true, audio: buffer } } to generate(), the following happens inside runStandardGenerateRequest() before the LLM call:\nProviderRegistry.isRegistered() is checked; if false, registerAllProviders() is awaited.\nSTTProcessor is dynamically imported and transcribe(audio, providerName, sttOptions) is called.\nThe transcription text is injected into the LLM prompt:\nIf no user text exists, the transcription becomes the prompt directly.\nIf user text exists, the transcription is prepended as [Transcribed audio]: <text>\\n\\n<user text>.\ngenerateResult.transcription is set to the STTResult object (available to callers).\nFailure-handling — split by whether the caller provided text:\nAudio-only requests (stt.audio present, no user text) — transcription failures fail fast: STTError propagates and generate() rejects, since there is no fallback prompt.\nText + audio requests — transcription failures are logged via logger.error and generate() continues with the un-augmented user text (preserves the optional-augmentation contract).\n\nType organisation\n\nThree new canonical type files added to src/lib/types/ (CLAUDE.md rule #8 compliant — no \"Types\" suffix):\n\n| File | Contents |\n| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| src/lib/types/tts.ts | Extended AudioFormat (added m4a, flac, webm, mp4, mpeg, mpga); added TTSOptions.provider field |\n| src/lib/types/stt.ts | STTHandler, STTOptions, STTResult, STTLanguage, WordTiming, TranscriptionSegment, STT_ERROR_CODES, DEFAULT_STT_OPTIONS, guards |\n| src/lib/types/realtime.ts | RealtimeHandler, RealtimeConfig, RealtimeSession, RealtimeAudioChunk, RealtimeSessionState, REALTIME_ERROR_CODES, DEFAULT_REALTIME_CONFIG |\n| src/lib/types/voice.ts | Aggregator: re-exports all of tts.ts, stt.ts, realtime.ts; adds VoiceCapability, VoiceProviderName, VoiceProviderConfig, VoiceErrorOptions |\n\nsrc/lib/types/index.ts gets two new export * lines (for stt.ts and realtime.ts; voice.ts is already present). All rules 9 and 10 apply: type names are globally unique, barrel uses export * only.\n\nTTS Providers Added\n\nopenai-tts\nFile: src/lib/voice/providers/OpenAITTS.ts (253 lines, NEW)\nClass: OpenAITTS implements TTSHandler\nAPI: POST https://api.openai.com/v1/audio/speech\nAuth: Authorization: Bearer $OPENAI_API_KEY\nModels: tts-1 (standard, default) and tts-1-hd (high quality; selected when options.quality === \"hd\")\nVoices (6): alloy, echo, fable, onyx, nova, shimmer\nOutput formats: mp3 (default), wav, opus/ogg (mapped to OpenAI's opus)\nMax text: 4 096 characters\nRegistered as: \"openai-tts\" in TTSProcessor\nTimeout: 30-second AbortController on every fetch call; throws TTSError with TTS_ERROR_CODES.SYNTHESIS_FAILED on abort\n\nelevenlabs\nFile: src/lib/voice/providers/ElevenLabsTTS.ts (326 lines, NEW)\nClass: ElevenLabsTTS implements TTSHandler\nAPI: POST https://api.elevenlabs.io/v1/text-to-speech/{voice_id}?output_format=...\nAuth: xi-api-key: $ELEVENLABS_API_KEY\nModel: eleven_multilingual_v2 (default; ELEVENLABS_MODEL overrides, a per-call model wins)\nVoices: Dynamic — fetched from /v1/voices and cached for 5 minutes. Default voice: 21m00Tcm4TlvDq8ikWAM (Rachel; ELEVENLABS_VOICE_ID overrides, a per-call voice wins).\nOutput formats: mp3_44100_<mp3Bitrat","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"","lvl3":""}},
9390
9404
  {"objectID":"f1716886f4d2be72b3a390632de3b8a02af44b3b6eceee234945f784b8be0362","title":"14 · Voice / Speech Integration — Implementation Journal","url":"/docs/provider-integration/14-voice-speech-integration#14-voice-speech-integration-implementation-journal","content":"Commit: 27a31c32 — feat(voice): add multi-provider TTS, STT, and realtime voice integration","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"14 · Voice / Speech Integration — Implementation Journal","lvl3":""}},
9391
9405
  {"objectID":"b3dc7153f1e7ef738b53d8523aba16e8c3fdef00abcdcf24457daff4cd1ccf1c","title":"How voice plugs into Factory + Registry","url":"/docs/provider-integration/14-voice-speech-integration#how-voice-plugs-into-factory-registry","content":"The voice integration does not add AI providers (it adds no entries to AIProviderName). Instead it introduces three parallel static registries that mirror the ProviderFactory / ProviderRegistry pattern for non-LLM capabilities:\n\nEach processor exposes registerHandler(name, handler) and the appropriate operation (synthesize, transcribe, connect). The same O(1) Map lookup and lazy-instantiation pattern used by ProviderRegistry applies here.","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"How voice plugs into Factory + Registry","lvl3":""}},
9392
9406
  {"objectID":"7c6ccdec7b0222fec9c2a63761524183b2b9a02080582f010c9ac3680bd2c3a5","title":"Registration location","url":"/docs/provider-integration/14-voice-speech-integration#registration-location","content":"All handler registration happens at the bottom of ProviderRegistry.registerAllProviders() in src/lib/factories/providerRegistry.ts, after all LLM providers are registered. The order is:\nLLM providers (existing)\nTTS handler registration block\nSTT handler registration block\nRealtime handler registration block\n\nEach block uses a separate try/catch so a missing API key or a broken import cannot prevent the LLM providers from registering. Registration is fire-and-forget: failures log a warn and continue.\n\nAll imports inside the registration blocks are dynamic (await import(...)), matching CLAUDE.md rule #1 and preventing circular dependencies.","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"Registration location","lvl3":""}},
9393
9407
  {"objectID":"972521392d4425027fffcd4dd5b35f38ee845ab94e8397c8fb6e69be6c55182e","title":"STT preprocessing in neurolink.ts runStandardGenerateRequest()","url":"/docs/provider-integration/14-voice-speech-integration#stt-preprocessing-in-neurolinkts-runstandardgeneraterequest","content":"When a caller passes { stt: { enabled: true, audio: buffer } } to generate(), the following happens inside runStandardGenerateRequest() before the LLM call:\nProviderRegistry.isRegistered() is checked; if false, registerAllProviders() is awaited.\nSTTProcessor is dynamically imported and transcribe(audio, providerName, sttOptions) is called.\nThe transcription text is injected into the LLM prompt:\nIf no user text exists, the transcription becomes the prompt directly.\nIf user text exists, the transcription is prepended as [Transcribed audio]: <text>\\n\\n<user text>.\ngenerateResult.transcription is set to the STTResult object (available to callers).\nFailure-handling — split by whether the caller provided text:\nAudio-only requests (stt.audio present, no user text) — transcription failures fail fast: STTError propagates and generate() rejects, since there is no fallback prompt.\nText + audio requests — transcription failures are logged via logger.error and generate() continues with the un-augmented user text (preserves the optional-augmentation contract).","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"STT preprocessing in neurolink.ts runStandardGenerateRequest()","lvl3":""}},
9394
9408
  {"objectID":"dc6bfff76f5d7a7a126364625fdf4f5636328289090eb27757a574a1516ae41b","title":"Type organisation","url":"/docs/provider-integration/14-voice-speech-integration#type-organisation","content":"Three new canonical type files added to src/lib/types/ (CLAUDE.md rule #8 compliant — no \"Types\" suffix):\n\n| File | Contents |\n| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| src/lib/types/tts.ts | Extended AudioFormat (added m4a, flac, webm, mp4, mpeg, mpga); added TTSOptions.provider field |\n| src/lib/types/stt.ts | STTHandler, STTOptions, STTResult, STTLanguage, WordTiming, TranscriptionSegment, STT_ERROR_CODES, DEFAULT_STT_OPTIONS, guards |\n| src/lib/types/realtime.ts | RealtimeHandler, RealtimeConfig, RealtimeSession, RealtimeAudioChunk, RealtimeSessionState, REALTIME_ERROR_CODES, DEFAULT_REALTIME_CONFIG |\n| src/lib/types/voice.ts | Aggregator: re-exports all of tts.ts, stt.ts, realtime.ts; adds VoiceCapability, VoiceProviderName, VoiceProviderConfig, VoiceErrorOptions |\n\nsrc/lib/types/index.ts gets two new export * lines (for stt.ts and realtime.ts; voice.ts is already present). All rules 9 and 10 apply: type names are globally unique, barrel uses export * only.","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"Type organisation","lvl3":""}},
9395
9409
  {"objectID":"82121793586ce9a42f376ea57200262313b86e1c364f2b982b7bc2be4b330d03","title":"openai-tts","url":"/docs/provider-integration/14-voice-speech-integration#openai-tts","content":"File: src/lib/voice/providers/OpenAITTS.ts (253 lines, NEW)\nClass: OpenAITTS implements TTSHandler\nAPI: POST https://api.openai.com/v1/audio/speech\nAuth: Authorization: Bearer $OPENAI_API_KEY\nModels: tts-1 (standard, default) and tts-1-hd (high quality; selected when options.quality === \"hd\")\nVoices (6): alloy, echo, fable, onyx, nova, shimmer\nOutput formats: mp3 (default), wav, opus/ogg (mapped to OpenAI's opus)\nMax text: 4 096 characters\nRegistered as: \"openai-tts\" in TTSProcessor\nTimeout: 30-second AbortController on every fetch call; throws TTSError with TTS_ERROR_CODES.SYNTHESIS_FAILED on abort","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"openai-tts","lvl3":""}},
9396
- {"objectID":"46d715e7d48dd11164b9942103cc32823b9215a02b01b1f36cadea8fe1321a9d","title":"elevenlabs","url":"/docs/provider-integration/14-voice-speech-integration#elevenlabs","content":"File: src/lib/voice/providers/ElevenLabsTTS.ts (326 lines, NEW)\nClass: ElevenLabsTTS implements TTSHandler\nAPI: POST https://api.elevenlabs.io/v1/text-to-speech/{voice_id}?output_format=...\nAuth: xi-api-key: $ELEVENLABS_API_KEY\nModel: eleven_multilingual_v2 (default)\nVoices: Dynamic — fetched from /v1/voices and cached for 5 minutes. Default voice: 21m00Tcm4TlvDq8ikWAM (Rachel).\nOutput formats: mp3_44100_128 (mp3), pcm_44100 (wav), ogg_22050 (ogg/opus)\nVoice settings: stability (default 0.5), similarity_boost (0.75), style (0.0), use_speaker_boost (true)\nMax text: 5 000 characters\nRegistered as: \"elevenlabs\" and \"elevenlabs-tts\" in TTSProcessor\nTimeout: 30-second AbortController on synthesize and getVoices calls","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"elevenlabs","lvl3":""}},
9410
+ {"objectID":"46d715e7d48dd11164b9942103cc32823b9215a02b01b1f36cadea8fe1321a9d","title":"elevenlabs","url":"/docs/provider-integration/14-voice-speech-integration#elevenlabs","content":"File: src/lib/voice/providers/ElevenLabsTTS.ts (326 lines, NEW)\nClass: ElevenLabsTTS implements TTSHandler\nAPI: POST https://api.elevenlabs.io/v1/text-to-speech/{voice_id}?output_format=...\nAuth: xi-api-key: $ELEVENLABS_API_KEY\nModel: eleven_multilingual_v2 (default; ELEVENLABS_MODEL overrides, a per-call model wins)\nVoices: Dynamic — fetched from /v1/voices and cached for 5 minutes. Default voice: 21m00Tcm4TlvDq8ikWAM (Rachel; ELEVENLABS_VOICE_ID overrides, a per-call voice wins).\nOutput formats: mp3_44100_<mp3Bitrate> (mp3, default 128), pcm_44100 (wav — raw PCM, reported as pcm16), opus_48000_<opusBitrate> (ogg/opus, default 64). There is no ogg_* family; bitrates outside 32|64|96|128|192 fall back to the default.\nVoice settings: stability (default 0.5), similarity_boost (0.75), style (0.0), use_speaker_boost (true), speed (from TTSOptions.speed, clamped to 0.7–1.2)\nLanguage: language / languageCode is reduced to ISO 639-1 and sent as language_code on every model but eleven_multilingual_v2\nMax text: 5 000 characters\nRegistered as: \"elevenlabs\" and \"elevenlabs-tts\" in TTSProcessor\nTimeout & retries: per-attempt timeoutMs (default 30 s, covering the audio body) with retries (default 1) on 429/5xx/timeout/transport failure, honouring Retry-After; a caller signal aborts the attempt and the loop. getVoices keeps a fixed 30 s AbortController.\nSTT: src/lib/voice/providers/ElevenLabsSTT.ts — Scribe batch transcription (POST /v1/speech-to-text, default scribe_v2), registered as \"elevenlabs-stt\" with aliases \"scribe\" and \"elevenlabs\" in STTProcessor","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"elevenlabs","lvl3":""}},
9397
9411
  {"objectID":"a2ccdfb8645467404aa8b754630b28bec4cadf510aa51c0e138554d5ddfa5876","title":"azure-tts","url":"/docs/provider-integration/14-voice-speech-integration#azure-tts","content":"File: src/lib/voice/providers/AzureTTS.ts (357 lines, NEW)\nClass: AzureTTS implements TTSHandler\nAPI: POST https://{region}.tts.speech.microsoft.com/cognitiveservices/v1\nAuth: Ocp-Apim-Subscription-Key: $AZURE_SPEECH_KEY\nRegion: $AZURE_SPEECH_REGION (default \"eastus\")\nDefault voice: en-US-JennyNeural\nOutput format (default): audio-24khz-96kbitrate-mono-mp3\nSSML: The handler builds SSML automatically from text, voice, speed, and pitch options. Callers can pass raw SSML by setting text to a string starting with <speak or by providing options.ssmlTemplate.\nVoices: Fetched from /cognitiveservices/voices/list and cached for 30 minutes.\nMax text: 10 000 characters\nRegistered as: \"azure-tts\" in TTSProcessor\nTimeout: 30-second AbortController on all fetch calls","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"azure-tts","lvl3":""}},
9398
9412
  {"objectID":"c3992086c4c3199c6a7584e632eab50e26a19eab0c15776417db8fc76d743f90","title":"whisper / openai-stt","url":"/docs/provider-integration/14-voice-speech-integration#whisper-openai-stt","content":"File: src/lib/voice/providers/OpenAISTT.ts (317 lines, NEW)\nClass: OpenAISTT implements STTHandler (exported also as WhisperSTT, WhisperSTTHandler, OpenAISTTHandler)\nAPI: POST https://api.openai.com/v1/audio/transcriptions (or /translations when translate: true)\nAuth: Authorization: Bearer $OPENAI_API_KEY\nModel: whisper-1 (default)\nResponse format: verbose_json (default) — returns text, language, duration, words, segments\nWord timestamps: Enabled when options.wordTimestamps === true (sends timestamp_granularities[]=word&segment)\nConfidence: Fixed at 0.95 (Whisper does not return per-result confidence); segment confidence derived from Math.exp(segment.avg_logprob)\nMax audio: 25 minutes\nSupported formats: mp3, wav, ogg, opus\nStreaming: Not supported (supportsStreaming = false)\nRegistered as: \"whisper\" and \"openai-stt\" in STTProcessor\nTimeout: 30-second AbortController on the fetch multipart form POST","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"whisper / openai-stt","lvl3":""}},
9399
9413
  {"objectID":"58b3eef88fc29f91a3207b1a38188cde25e8c383a1e489230023f1b4a263656e","title":"google-stt","url":"/docs/provider-integration/14-voice-speech-integration#google-stt","content":"File: src/lib/voice/providers/GoogleSTT.ts (481 lines, NEW)\nClass: GoogleSTT implements STTHandler\nAPI: POST https://speech.googleapis.com/v1/speech:recognize\nAuth: $GOOGLE_API_KEY (query param) or $GOOGLE_APPLICATION_CREDENTIALS (service account path)\nStreaming: Supported (supportsStreaming = true)\nMax audio: 480 minutes (8 hours, async path)\nDiarization: Supported\nRegistered as: \"google-stt\" in STTProcessor\nTimeout: 30-second AbortController","hierarchy":{"lvl0":"Provider Integration","lvl1":"14 · Voice / Speech Integration — Implementation Journal","lvl2":"google-stt","lvl3":""}},
@@ -10867,7 +10881,7 @@
10867
10881
  {"objectID":"efcf19aa651c13dbc72ef4b3d0f83986ee180008a076c0db030509880e4d4b1a","title":"MCP Server Events","url":"/docs/sdk/api-reference#mcp-server-events","content":"| Event | Emitted When |\n| -------------------------------- | ----------------------------------------- |\n| externalMCP:serverConnected | An external MCP server connects |\n| externalMCP:serverDisconnected | An external MCP server disconnects |\n| externalMCP:serverFailed | An external MCP server connection fails |\n| externalMCP:toolDiscovered | A new tool is discovered on an MCP server |\n| externalMCP:toolRemoved | A tool is removed from an MCP server |\n| externalMCP:serverAdded | A new MCP server registration is added |\n| externalMCP:serverRemoved | An MCP server registration is removed |","hierarchy":{"lvl0":"Sdk","lvl1":"API Reference","lvl2":"MCP Server Events","lvl3":""}},
10868
10882
  {"objectID":"c4d157804d0d96f1d8571e6aabeff4305aca0c07c151894dee3804d611331de6","title":"Other Events","url":"/docs/sdk/api-reference#other-events","content":"| Event | Emitted When |\n| ---------------------- | ----------------------------------- |\n| tools-register:start | Tool registration process begins |\n| tools-register:end | Tool registration process completes |\n| connected | Connection established |\n| message | General message event |\n| error | An error occurs |\n| log | A log message is emitted |\n| log-event | A structured log event is emitted |\n\nTypedEventEmitter Interface:","hierarchy":{"lvl0":"Sdk","lvl1":"API Reference","lvl2":"Other Events","lvl3":""}},
10869
10883
  {"objectID":"7ff1b31f163c4928ce88a79da3c279d1c1c6351ccf3cc5ad2464d2a03174f308","title":"Related Features","url":"/docs/sdk/api-reference#related-features","content":"Human-in-the-Loop (HITL) - Mark tools with requiresConfirmation: true\nGuardrails Middleware - Enable with middleware: { preset: 'security' }\nConversation History - Use getConversationHistory() method\nMultimodal Chat - Use images array in generate() options\nAuto Evaluation - Enable with enableEvaluation: true\nCLI Loop Sessions - Interactive mode with persistent state\nProvider Orchestration - Set enableOrchestration: true\nRegional Streaming - Use region parameter in generate()\nOffice Documents - Use officeFiles array for DOCX, PPTX, XLSX\nPDF Support - Use pdfFiles array for PDF documents\nCSV Support - Use csvFiles array for spreadsheet data\nCLI Commands Reference - CLI equivalents for all SDK methods\nConfiguration Guide - Environment variables and config files\nTroubleshooting - Common SDK issues and solutions\n\nBack to Main README | Next: Visual Demos","hierarchy":{"lvl0":"Sdk","lvl1":"API Reference","lvl2":"Related Features","lvl3":""}},
10870
- {"objectID":"72ff7213f71cd3e590c196c5a1a39a7ab2af152776936e1a647f228cae34de6e","title":"🔧 SDK Custom Tools Guide","url":"/docs/sdk/custom-tools-guide","content":"🔧 SDK Custom Tools Guide\n\nBuild powerful AI applications by extending NeuroLink with your own custom tools.\n\n📋 Overview\n\nNeuroLink's SDK allows you to register custom tools programmatically, giving your AI assistants access to any functionality you need. All registered tools work seamlessly with the built-in tool system across all supported providers.\n\nKey Features\n✅ Type-Safe: Full TypeScript support with Zod schema validation\n✅ Provider Agnostic: Works with all providers that support tools\n✅ Easy Integration: Simple API for tool registration\n✅ Async Support: All tools run asynchronously\n✅ Error Handling: Graceful error handling built-in\n\n🚀 Quick Start\n\nBasic Tool Registration\n\n⚠️ Common Mistakes\n\n❌ Using schema instead of parameters\n\n❌ Using plain JSON schema as parameters\n\n✅ Correct Zod Schema Format\n\n📖 SimpleTool Interface\n\nAll custom tools implement the SimpleTool interface:\n\nInterface Components\ndescription: Clear, actionable description that helps the AI understand when to use the tool\nparameters: Optional Zod schema for validating inputs (highly recommended)\nexecute: Async function that implements the tool's logic\n\n🛠️ Registration Methods\n\nRegister Single Tool\n\nRegister Multiple Tools\n\nGet Custom Tools\n\n💡 Common Use Cases\nAPI Integration\nDatabase Operations\nData Processing\nFile Operations\nExternal Service Integration\n\n🎯 Best Practices\nClear Descriptions\n\nMake tool descriptions specific and actionable:\nParameter Validation\n\nAlways use Zod schemas for type safety:\nError Handling\n\nHandle errors gracefully:\nAsync Operations\n\nAll execute functions must return promises:\nTool Naming\n\nUse clear, consistent naming:\n\n🧪 Testing Your Tools\n\nUnit Testing\n\nIntegration Testing\n\n🔍 Debugging Tools\n\nEnable Debug Mode\n\nLog Tool Execution\n\n🚀 Advanced Patterns\n\nTool Composition\n\nTool Middleware\n\nDynamic Tool Registration\n\n📊 Performance Considerations\nTimeout Handling\nCaching\nBatch Operations\n\n🔒 Security Considerations\n\nInput Sanitization\n\nPermission Checking\n\nRate Limiting\n\n🎉 Complete Example\n\nHere's a complete example combining multiple concepts:\n\n🌐 MCP Server Integration\n\nBeyond simple tool registration, NeuroLink SDK supports adding complete MCP (Model Context Protocol) servers for more complex tool ecosystems.\n\nAdding In-Memory MCP Servers\n\nAdvanced MCP Server Examples\nData Analytics Server\nWorkflow Automation Server\nContent Generation Server\n\nMixed Tool Ecosystem Example\n\nTool Discovery and Management\n\nAdding Remote HTTP MCP Servers\n\nConnect to remote MCP servers via HTTP transport with authentication, retry, and rate limiting:\n\nHTTP Configuration Options:\n\n| Option | Type | Description |\n| -------------- | ------ | ------------------------------------------- |\n| transport | string | Must be \"http\" for HTTP transport |\n| url | string | Remote MCP endpoint URL |\n| headers | object | Custom HTTP headers |\n| httpOptions | object | Connection timeout settings |\n| retryConfig | object | Retry with exponential backoff |\n| rateLimiting | object | Rate limiting configuration |\n| auth | object | Authentication (OAuth 2.1, Bearer, API Key) |\n\nSee MCP HTTP Transport Guide for complete documentation.\n\nBest Practices for MCP Integration\nOrganize Tools by Domain\nConsistent Error Handling\nComprehensive Metadata\n\n📚 Additional Resources\nAPI Reference - NeuroLink Class\nMCP Integration Guide\nProvider Tool Support\nTest Examples\nMCP SDK Integration Proof Tests\nReal AI-MCP Integration Demo\n\nStart building powerful AI applications with custom tools and MCP servers today! 🚀","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"","lvl3":""}},
10884
+ {"objectID":"72ff7213f71cd3e590c196c5a1a39a7ab2af152776936e1a647f228cae34de6e","title":"🔧 SDK Custom Tools Guide","url":"/docs/sdk/custom-tools-guide","content":"🔧 SDK Custom Tools Guide\n\nBuild powerful AI applications by extending NeuroLink with your own custom tools.\n\n📋 Overview\n\nNeuroLink's SDK allows you to register custom tools programmatically, giving your AI assistants access to any functionality you need. All registered tools work seamlessly with the built-in tool system across all supported providers.\n\nKey Features\n✅ Type-Safe: Full TypeScript support with Zod schema validation\n✅ Provider Agnostic: Works with all providers that support tools\n✅ Easy Integration: Simple API for tool registration\n✅ Async Support: All tools run asynchronously\n✅ Error Handling: Graceful error handling built-in\n\n🚀 Quick Start\n\nBasic Tool Registration\n\n⚠️ Common Mistakes\n\n❌ Using schema instead of parameters\n\n❌ Using plain JSON schema as parameters\n\n✅ Correct Zod Schema Format\n\n📖 SimpleTool Interface\n\nAll custom tools implement the SimpleTool interface:\n\nInterface Components\ndescription: Clear, actionable description that helps the AI understand when to use the tool\nparameters: Optional Zod schema for validating inputs (highly recommended)\nexecute: Async function that implements the tool's logic\n\n🛠️ Registration Methods\n\nRegister Single Tool\n\nRegister Multiple Tools\n\nGet Custom Tools\n\n💡 Common Use Cases\nAPI Integration\nDatabase Operations\nData Processing\nFile Operations\nExternal Service Integration\n\n🎯 Best Practices\nClear Descriptions\n\nMake tool descriptions specific and actionable:\nParameter Validation\n\nAlways use Zod schemas for type safety:\nError Handling\n\nHandle errors gracefully:\n\nA returned error is classified as a failure everywhere the SDK reports one,\nexactly as a thrown error is. A result is error-shaped when it carries\nisError: true (the MCP convention), a non-null error field ({ error:\n\"User not found\" }), or a status of \"error\" / \"failed\" / \"failure\" /\n\"fail\". Such a call emits tool:end with success: false and the error\ntext, is stored in session memory as success: false, replays on later turns\nas [called <tool> → error], and is reported with isError: true in\nresult.toolExecutions. The model still receives the full object you\nreturned — classification only affects telemetry and memory, never what the\nmodel sees.\nAsync Operations\n\nAll execute functions must return promises:\nTool Naming\n\nUse clear, consistent naming:\n\n🧪 Testing Your Tools\n\nUnit Testing\n\nIntegration Testing\n\n🔍 Debugging Tools\n\nEnable Debug Mode\n\nLog Tool Execution\n\n🚀 Advanced Patterns\n\nTool Composition\n\nTool Middleware\n\nDynamic Tool Registration\n\nForcing a Tool Call\n\ntoolChoice tells the model whether it must call a tool on a step:\n\n| Value | Effect |\n| --------------------------------- | ------------------------------------------------ |\n| \"auto\" (default) | The model decides whether and which tool to call |\n| \"none\" | No tool calls on any step |\n| \"required\" | The model must call at least one tool |\n| { type: \"tool\", toolName: \"x\" } | The model must call the named tool |\n\nA forced choice (\"required\" or a named tool) is applied only to the first\ntoolChoiceSteps steps of the tool loop — default 1 — after which the\nmodel is free to answer. Holding a forced choice on every step would compel\na tool call on every step, and the turn could only end when maxSteps ran\nout. \"auto\" and \"none\" are applied unchanged on every step.\n\nFor anything finer, prepareStep runs before every step and may return a\ntoolChoice for that step, which takes precedence over toolChoiceSteps:\n\nprepareStep receives { stepNumber, steps, maxSteps, model }, where steps\nholds one record per completed step (its text, tool calls — with input\nalready parsed into an object — tool results, finish reason and usage,\nincluding prompt-cache tokens where the provider reports them). Only the\nreturned toolChoice is honoured; the legacy model and\nexperimental_activeTools / activeTools fields are accepted for source\ncompatibility but ignored, and their presence is logged once as a warning —\nuse toolFilter / excludeTools to scope tools. A hook that throws is\nlogged and that step falls back to the toolChoice / toolChoiceSteps rule;\na hook still pending when the turn is aborted or times out is released with\nthe abort. Both toolChoice and prepareStep apply to stream() as well.\n\nVertex, Google AI Studio and Bedrock do not honour toolChoice at all today.\nSageMaker honours tools, toolChoice and prepareStep on generate()\nonly: its stream() sends the prompt without tools.\n\n📊 Performance Considerations\nTimeout Handling\nCaching\nBatch Operations\n\n🔒 Security Considerations\n\nInput Sanitization\n\nPermission Checking\n\nRate Limiting\n\n🎉 Complete Example\n\nHere's a complete example combining multiple concepts:\n\n🌐 MCP Server Integration\n\nBeyond simple tool registration, NeuroLink SDK supports adding complete MCP (Model Context Protocol) servers for more complex tool ecosystems.\n\nAdding I","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"","lvl3":""}},
10871
10885
  {"objectID":"fe570104af53b04cac97749a24ce61018428abe7df180a14a7285ebf6fda6fca","title":"🔧 SDK Custom Tools Guide","url":"/docs/sdk/custom-tools-guide#-sdk-custom-tools-guide","content":"Build powerful AI applications by extending NeuroLink with your own custom tools.","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"🔧 SDK Custom Tools Guide","lvl3":""}},
10872
10886
  {"objectID":"4c744b8358a0761297815b9e1244bad43bebb4ece00ddac4cb24b186dbae5647","title":"📋 Overview","url":"/docs/sdk/custom-tools-guide#-overview","content":"NeuroLink's SDK allows you to register custom tools programmatically, giving your AI assistants access to any functionality you need. All registered tools work seamlessly with the built-in tool system across all supported providers.","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"📋 Overview","lvl3":""}},
10873
10887
  {"objectID":"010108554678126b2dfa7412be816dcd177027c52ab9e37d41fe8990f52af4b2","title":"Key Features","url":"/docs/sdk/custom-tools-guide#key-features","content":"✅ Type-Safe: Full TypeScript support with Zod schema validation\n✅ Provider Agnostic: Works with all providers that support tools\n✅ Easy Integration: Simple API for tool registration\n✅ Async Support: All tools run asynchronously\n✅ Error Handling: Graceful error handling built-in","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"Key Features","lvl3":""}},
@@ -10875,9 +10889,10 @@
10875
10889
  {"objectID":"2ef8e164969dd7ddf44f75ee039aef0808a65c02b32f7f3e27ed1a6c006fda03","title":"Interface Components","url":"/docs/sdk/custom-tools-guide#interface-components","content":"description: Clear, actionable description that helps the AI understand when to use the tool\nparameters: Optional Zod schema for validating inputs (highly recommended)\nexecute: Async function that implements the tool's logic","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"Interface Components","lvl3":""}},
10876
10890
  {"objectID":"0d3359018d7dcdf244d2aeb451db36629c342b9eb3ed508fd72bb864d785996a","title":"1. Clear Descriptions","url":"/docs/sdk/custom-tools-guide#1-clear-descriptions","content":"Make tool descriptions specific and actionable:","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"1. Clear Descriptions","lvl3":""}},
10877
10891
  {"objectID":"3e9e3114d4c2aaa19c8c9e57a44c8613b702ff503e458dd171a3864aa105e8e2","title":"2. Parameter Validation","url":"/docs/sdk/custom-tools-guide#2-parameter-validation","content":"Always use Zod schemas for type safety:","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"2. Parameter Validation","lvl3":""}},
10878
- {"objectID":"a4a53f285dce3dd5d8a27f73ba485c4c45c18758dab19b09b03b642e03300b01","title":"3. Error Handling","url":"/docs/sdk/custom-tools-guide#3-error-handling","content":"Handle errors gracefully:","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"3. Error Handling","lvl3":""}},
10892
+ {"objectID":"a4a53f285dce3dd5d8a27f73ba485c4c45c18758dab19b09b03b642e03300b01","title":"3. Error Handling","url":"/docs/sdk/custom-tools-guide#3-error-handling","content":"Handle errors gracefully:\n\nA returned error is classified as a failure everywhere the SDK reports one,\nexactly as a thrown error is. A result is error-shaped when it carries\nisError: true (the MCP convention), a non-null error field ({ error:\n\"User not found\" }), or a status of \"error\" / \"failed\" / \"failure\" /\n\"fail\". Such a call emits tool:end with success: false and the error\ntext, is stored in session memory as success: false, replays on later turns\nas [called <tool> → error], and is reported with isError: true in\nresult.toolExecutions. The model still receives the full object you\nreturned — classification only affects telemetry and memory, never what the\nmodel sees.","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"3. Error Handling","lvl3":""}},
10879
10893
  {"objectID":"6d53d5c8c4d05f521154f2dc2c0bed40d84bfba748ece9d2c361c6d9ff73754c","title":"4. Async Operations","url":"/docs/sdk/custom-tools-guide#4-async-operations","content":"All execute functions must return promises:","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"4. Async Operations","lvl3":""}},
10880
10894
  {"objectID":"bb568588b9dcf32f03267d65246c0d0400a369f569b2a94c3cbc03e27d3644d7","title":"5. Tool Naming","url":"/docs/sdk/custom-tools-guide#5-tool-naming","content":"Use clear, consistent naming:","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"5. Tool Naming","lvl3":""}},
10895
+ {"objectID":"1d45fc9282e105f34492f449d1dcdbc250e17e5a15eefc297b8573e567092a44","title":"Forcing a Tool Call","url":"/docs/sdk/custom-tools-guide#forcing-a-tool-call","content":"toolChoice tells the model whether it must call a tool on a step:\n\n| Value | Effect |\n| --------------------------------- | ------------------------------------------------ |\n| \"auto\" (default) | The model decides whether and which tool to call |\n| \"none\" | No tool calls on any step |\n| \"required\" | The model must call at least one tool |\n| { type: \"tool\", toolName: \"x\" } | The model must call the named tool |\n\nA forced choice (\"required\" or a named tool) is applied only to the first\ntoolChoiceSteps steps of the tool loop — default 1 — after which the\nmodel is free to answer. Holding a forced choice on every step would compel\na tool call on every step, and the turn could only end when maxSteps ran\nout. \"auto\" and \"none\" are applied unchanged on every step.\n\nFor anything finer, prepareStep runs before every step and may return a\ntoolChoice for that step, which takes precedence over toolChoiceSteps:\n\nprepareStep receives { stepNumber, steps, maxSteps, model }, where steps\nholds one record per completed step (its text, tool calls — with input\nalready parsed into an object — tool results, finish reason and usage,\nincluding prompt-cache tokens where the provider reports them). Only the\nreturned toolChoice is honoured; the legacy model and\nexperimental_activeTools / activeTools fields are accepted for source\ncompatibility but ignored, and their presence is logged once as a warning —\nuse toolFilter / excludeTools to scope tools. A hook that throws is\nlogged and that step falls back to the toolChoice / toolChoiceSteps rule;\na hook still pending when the turn is aborted or times out is released with\nthe abort. Both toolChoice and prepareStep apply to stream() as well.\n\nVertex, Google AI Studio and Bedrock do not honour toolChoice at all today.","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"Forcing a Tool Call","lvl3":""}},
10881
10896
  {"objectID":"74925ba0e67d71ad745857d081af424fb56d532f0da8d4e1f794644ebc422e8c","title":"🎉 Complete Example","url":"/docs/sdk/custom-tools-guide#-complete-example","content":"Here's a complete example combining multiple concepts:","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"🎉 Complete Example","lvl3":""}},
10882
10897
  {"objectID":"82711474e0112283b156bda3988c63baf1430415b74067f02e288d321def21ef","title":"🌐 MCP Server Integration","url":"/docs/sdk/custom-tools-guide#-mcp-server-integration","content":"Beyond simple tool registration, NeuroLink SDK supports adding complete MCP (Model Context Protocol) servers for more complex tool ecosystems.","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"🌐 MCP Server Integration","lvl3":""}},
10883
10898
  {"objectID":"1a2e68a29445c12992a8f472886e22b3b328840b7ee6dae4bf362398a7b1e19a","title":"Adding Remote HTTP MCP Servers","url":"/docs/sdk/custom-tools-guide#adding-remote-http-mcp-servers","content":"Connect to remote MCP servers via HTTP transport with authentication, retry, and rate limiting:\n\nHTTP Configuration Options:\n\n| Option | Type | Description |\n| -------------- | ------ | ------------------------------------------- |\n| transport | string | Must be \"http\" for HTTP transport |\n| url | string | Remote MCP endpoint URL |\n| headers | object | Custom HTTP headers |\n| httpOptions | object | Connection timeout settings |\n| retryConfig | object | Retry with exponential backoff |\n| rateLimiting | object | Rate limiting configuration |\n| auth | object | Authentication (OAuth 2.1, Bearer, API Key) |\n\nSee MCP HTTP Transport Guide for complete documentation.","hierarchy":{"lvl0":"Sdk","lvl1":"🔧 SDK Custom Tools Guide","lvl2":"Adding Remote HTTP MCP Servers","lvl3":""}},