@juspay/neurolink 12.59.0 → 13.0.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 (146) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/dist/auth/anthropicOAuth.js +3 -3
  3. package/dist/auth/middleware/AuthMiddleware.d.ts +1 -1
  4. package/dist/auth/sessionManager.js +4 -4
  5. package/dist/auth/tokenStore.js +4 -4
  6. package/dist/browser/neurolink.min.js +474 -473
  7. package/dist/cli/commands/observability.d.ts +1 -6
  8. package/dist/cli/commands/observability.js +0 -106
  9. package/dist/cli/commands/proxy.js +9 -18
  10. package/dist/cli/commands/telemetry.d.ts +3 -13
  11. package/dist/cli/commands/telemetry.js +7 -354
  12. package/dist/cli/loop/session.js +1 -1
  13. package/dist/client/httpClient.js +1 -1
  14. package/dist/client/sseClient.js +1 -1
  15. package/dist/client/streamingClient.js +2 -2
  16. package/dist/client/wsClient.js +1 -1
  17. package/dist/constants/langfuse.d.ts +25 -0
  18. package/dist/constants/langfuse.js +38 -0
  19. package/dist/constants/telemetry.d.ts +20 -0
  20. package/dist/constants/telemetry.js +34 -0
  21. package/dist/core/baseProvider.d.ts +2 -1
  22. package/dist/core/baseProvider.js +4 -11
  23. package/dist/core/conversationMemoryManager.js +5 -8
  24. package/dist/core/factory.js +1 -1
  25. package/dist/core/geminiLoopAdapter.d.ts +8 -1
  26. package/dist/core/geminiLoopAdapter.js +25 -1
  27. package/dist/core/loopEngine.js +69 -40
  28. package/dist/core/modules/MessageBuilder.js +2 -2
  29. package/dist/core/modules/StreamHandler.js +2 -2
  30. package/dist/core/modules/TelemetryHandler.d.ts +2 -18
  31. package/dist/core/modules/TelemetryHandler.js +1 -66
  32. package/dist/core/modules/ToolsManager.js +40 -31
  33. package/dist/core/nativeGenerateLoop.js +78 -8
  34. package/dist/core/redisConversationMemoryManager.js +8 -15
  35. package/dist/core/toolExecutionGuards.js +1 -13
  36. package/dist/index.d.ts +5 -12
  37. package/dist/index.js +5 -37
  38. package/dist/mcp/batching/requestBatcher.js +1 -1
  39. package/dist/mcp/externalServerManager.js +3 -21
  40. package/dist/mcp/toolDiscoveryService.js +4 -16
  41. package/dist/mcp/toolRegistry.js +2 -5
  42. package/dist/memory/memoryRetrievalTools.js +1 -1
  43. package/dist/neurolink.d.ts +16 -27
  44. package/dist/neurolink.js +788 -792
  45. package/dist/observability/exporterSpanProcessor.d.ts +50 -0
  46. package/dist/observability/exporterSpanProcessor.js +181 -0
  47. package/dist/observability/exporters/langfuseExporter.d.ts +13 -34
  48. package/dist/observability/exporters/langfuseExporter.js +101 -154
  49. package/dist/observability/index.d.ts +1 -0
  50. package/dist/observability/index.js +1 -0
  51. package/dist/observability/langfuseMasking.d.ts +8 -0
  52. package/dist/observability/langfuseMasking.js +47 -0
  53. package/dist/observability/otlpEncoding.d.ts +20 -0
  54. package/dist/observability/otlpEncoding.js +85 -0
  55. package/dist/providers/amazonBedrock/client.js +142 -176
  56. package/dist/providers/amazonBedrock/loopAdapter.js +14 -1
  57. package/dist/providers/amazonSagemaker.js +118 -80
  58. package/dist/providers/anthropic/client.js +3 -52
  59. package/dist/providers/anthropic/loopAdapter.js +24 -1
  60. package/dist/providers/anthropic/rateLimitCapture.js +9 -12
  61. package/dist/providers/googleAiStudio/client.d.ts +4 -5
  62. package/dist/providers/googleAiStudio/client.js +38 -40
  63. package/dist/providers/googleVertex/client.d.ts +2 -7
  64. package/dist/providers/googleVertex/client.js +282 -378
  65. package/dist/providers/googleVertex/constants.js +2 -2
  66. package/dist/providers/litellm/client.d.ts +2 -9
  67. package/dist/providers/litellm/client.js +1 -63
  68. package/dist/providers/openAI/client.d.ts +1 -8
  69. package/dist/providers/openAI/client.js +0 -65
  70. package/dist/providers/openaiChatCompletionsBase.d.ts +1 -0
  71. package/dist/providers/openaiChatCompletionsBase.js +61 -4
  72. package/dist/providers/replicate.js +22 -4
  73. package/dist/proxy/codexUsage.js +7 -0
  74. package/dist/proxy/proxyFetch.js +19 -25
  75. package/dist/proxy/proxyTracer.d.ts +14 -7
  76. package/dist/proxy/proxyTracer.js +129 -83
  77. package/dist/proxy/proxyTranslationEngine.js +0 -1
  78. package/dist/proxy/requestLogger.d.ts +1 -1
  79. package/dist/proxy/requestLogger.js +39 -45
  80. package/dist/server/middleware/auth.d.ts +5 -1
  81. package/dist/server/middleware/auth.js +10 -3
  82. package/dist/server/middleware/common.js +1 -1
  83. package/dist/server/routes/agentRoutes.js +4 -4
  84. package/dist/server/routes/claudeProxyRoutes.js +99 -196
  85. package/dist/server/routes/codexProxyRoutes.js +621 -591
  86. package/dist/server/routes/healthRoutes.js +6 -6
  87. package/dist/server/routes/mcpRoutes.js +7 -7
  88. package/dist/server/routes/memoryRoutes.js +7 -7
  89. package/dist/server/routes/openApiRoutes.js +3 -3
  90. package/dist/server/routes/toolRoutes.js +5 -5
  91. package/dist/server/routes/transcribeRoutes.js +1 -1
  92. package/dist/server/utils/validation.d.ts +3 -3
  93. package/dist/services/server/ai/observability/instrumentation.d.ts +34 -201
  94. package/dist/services/server/ai/observability/instrumentation.js +220 -1267
  95. package/dist/services/server/ai/observability/langfuseSetup.d.ts +14 -0
  96. package/dist/services/server/ai/observability/langfuseSetup.js +55 -0
  97. package/dist/services/server/ai/observability/otlpSetup.d.ts +16 -0
  98. package/dist/services/server/ai/observability/otlpSetup.js +58 -0
  99. package/dist/session/globalSessionState.js +0 -11
  100. package/dist/telemetry/attributes.d.ts +23 -46
  101. package/dist/telemetry/attributes.js +76 -162
  102. package/dist/telemetry/chatMessages.d.ts +13 -0
  103. package/dist/telemetry/chatMessages.js +59 -0
  104. package/dist/telemetry/index.d.ts +5 -19
  105. package/dist/telemetry/index.js +5 -26
  106. package/dist/telemetry/observation.d.ts +37 -0
  107. package/dist/telemetry/observation.js +112 -0
  108. package/dist/telemetry/observationNames.d.ts +18 -0
  109. package/dist/telemetry/observationNames.js +24 -0
  110. package/dist/telemetry/spanSanitizer.d.ts +39 -0
  111. package/dist/telemetry/spanSanitizer.js +92 -0
  112. package/dist/telemetry/spanSerialization.d.ts +13 -0
  113. package/dist/telemetry/spanSerialization.js +46 -0
  114. package/dist/telemetry/tracers.d.ts +37 -18
  115. package/dist/telemetry/tracers.js +97 -19
  116. package/dist/telemetry/withSpan.d.ts +47 -25
  117. package/dist/telemetry/withSpan.js +158 -71
  118. package/dist/types/cli.d.ts +0 -11
  119. package/dist/types/decision.d.ts +3 -0
  120. package/dist/types/exporter.d.ts +54 -0
  121. package/dist/types/exporter.js +0 -4
  122. package/dist/types/generate.d.ts +4 -1
  123. package/dist/types/isolatedAgent.d.ts +5 -4
  124. package/dist/types/loopEngine.d.ts +18 -28
  125. package/dist/types/observability.d.ts +127 -160
  126. package/dist/types/providers.d.ts +15 -0
  127. package/dist/types/proxy.d.ts +41 -2
  128. package/dist/types/server.d.ts +9 -5
  129. package/dist/utils/anthropicTraceSanitizer.d.ts +2 -2
  130. package/dist/utils/anthropicTraceSanitizer.js +3 -1
  131. package/dist/utils/conversationMemory.js +4 -4
  132. package/dist/utils/fileDetector.js +1 -1
  133. package/dist/utils/messageBuilder.js +1 -1
  134. package/dist/utils/noOutputSentinel.d.ts +4 -16
  135. package/dist/utils/noOutputSentinel.js +12 -28
  136. package/dist/utils/providerRetry.js +4 -4
  137. package/dist/voice/livekit/brain.js +1 -1
  138. package/dist/voice/livekit/realtimeMemory.d.ts +1 -1
  139. package/dist/voice/livekit/realtimeMemory.js +66 -1
  140. package/dist/voice/livekit/realtimeVoiceAgent.js +1 -1
  141. package/docs-site/static/search-index.json +42 -64
  142. package/package.json +5 -4
  143. package/dist/telemetry/telemetryService.d.ts +0 -79
  144. package/dist/telemetry/telemetryService.js +0 -572
  145. package/dist/utils/observabilityHelpers.d.ts +0 -27
  146. package/dist/utils/observabilityHelpers.js +0 -47
@@ -943,14 +943,11 @@
943
943
  {"objectID":"98f588d4c4ba41d2da53cf11ce8187893d979ce536be19ec42a82c03a48ddbca","title":"observability \\<subcommand\\>","url":"/docs/cli/commands#observability-subcommand","content":"Observability and telemetry management. Aliases: obs, otel.\n\n`bash","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"observability \\<subcommand\\>","lvl3":""}},
944
944
  {"objectID":"99a3e335628404f8be4bd598f7993c5a317bff2d68d2cd7321cc580345cc1f58","title":"Show telemetry and observability status","url":"/docs/cli/commands#show-telemetry-and-observability-status","content":"npx @juspay/neurolink observability status","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Show telemetry and observability status","lvl3":""}},
945
945
  {"objectID":"642e8cb1bd07f35e9c81fc2dc83d198bb72fb9975b78277028059bd46aeea24a","title":"Show metrics summary","url":"/docs/cli/commands#show-metrics-summary","content":"npx @juspay/neurolink obs metrics --detailed","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Show metrics summary","lvl3":""}},
946
- {"objectID":"8558677a8c5dab6f0793992e5209489803c177b181f09da1aecb37a7f1486853","title":"List configured exporters","url":"/docs/cli/commands#list-configured-exporters","content":"npx @juspay/neurolink otel exporters","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"List configured exporters","lvl3":""}},
947
- {"objectID":"a13ddc6e3c0c63db6b72b69c14d0da5bebb0ae99cf2c293cb04c2a642f1c5970","title":"Show cost breakdown","url":"/docs/cli/commands#show-cost-breakdown","content":"npx @juspay/neurolink observability costs --by-model\n\n\n**Subcommands:**\n\n| Subcommand | Alias | Description |\n| ----------- | ------ | --------------------------------------- |\n| status | | Show telemetry and observability status |\n| metrics | | Show metrics summary |\n| exporters | exp | List configured exporters |\n| costs | cost | Show cost breakdown |\n\n**Shared flags (all subcommands):**\n\n| Option | Alias | Type | Default | Description |\n| ---------- | ----- | ------- | ------- | -------------------------------------- |\n| --format | -f | string | text | Output format: text, json, table |\n| --quiet | -q | boolean | false | Minimal output |\n\n**metrics flags:**\n\n| Option | Alias | Type | Default | Description |\n| ------------ | ----- | ------- | ------- | ------------------------------------------- |\n| --detailed | -d | boolean | false | Show detailed metrics including percentiles |\n\n**costs flags:**\n\n| Option | Alias | Type | Default | Description |\n| --------------- | ----- | ------- | ------- | ------------------------------- |\n| --by-model | -m | boolean | true | Show cost breakdown by model |\n| --by-provider | -p | boolean | true` | Show cost breakdown by provider |","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Show cost breakdown","lvl3":""}},
948
- {"objectID":"86662492401672412d19481d6b54e38149130c9affeb8683bbc2452a3604cd01","title":"telemetry \\<subcommand\\>","url":"/docs/cli/commands#telemetry-subcommand","content":"Telemetry and exporter management. Alias: tel.\n\n`bash","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"telemetry \\<subcommand\\>","lvl3":""}},
949
- {"objectID":"e57314fb9bd962a082ee2f547148499c43f62baff7bd4f92c513aa927ca64a54","title":"Show exporter status and health","url":"/docs/cli/commands#show-exporter-status-and-health","content":"npx @juspay/neurolink telemetry status","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Show exporter status and health","lvl3":""}},
950
- {"objectID":"bc9bea109a3e705754817975cf7fae413b404b9af9b23f05234014ec5fe28820","title":"Configure an exporter","url":"/docs/cli/commands#configure-an-exporter","content":"npx @juspay/neurolink tel configure --exporter langfuse --config '{\"publicKey\":\"pk-...\",\"secretKey\":\"sk-...\"}'","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Configure an exporter","lvl3":""}},
951
- {"objectID":"c0485f0647b4e47e2199943b415fbdbca6bc929381e5ddb7d02e11a76c1cb2d7","title":"List all available and configured exporters","url":"/docs/cli/commands#list-all-available-and-configured-exporters","content":"npx @juspay/neurolink telemetry list-exporters","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"List all available and configured exporters","lvl3":""}},
946
+ {"objectID":"a13ddc6e3c0c63db6b72b69c14d0da5bebb0ae99cf2c293cb04c2a642f1c5970","title":"Show cost breakdown","url":"/docs/cli/commands#show-cost-breakdown","content":"npx @juspay/neurolink observability costs --by-model\n\n\n**Subcommands:**\n\n| Subcommand | Alias | Description |\n| ---------- | ------ | --------------------------------------- |\n| status | | Show telemetry and observability status |\n| metrics | | Show metrics summary |\n| costs | cost | Show cost breakdown |\n\n**Shared flags (all subcommands):**\n\n| Option | Alias | Type | Default | Description |\n| ---------- | ----- | ------- | ------- | -------------------------------------- |\n| --format | -f | string | text | Output format: text, json, table |\n| --quiet | -q | boolean | false | Minimal output |\n\n**metrics flags:**\n\n| Option | Alias | Type | Default | Description |\n| ------------ | ----- | ------- | ------- | ------------------------------------------- |\n| --detailed | -d | boolean | false | Show detailed metrics including percentiles |\n\n**costs flags:**\n\n| Option | Alias | Type | Default | Description |\n| --------------- | ----- | ------- | ------- | ------------------------------- |\n| --by-model | -m | boolean | true | Show cost breakdown by model |\n| --by-provider | -p | boolean | true` | Show cost breakdown by provider |","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Show cost breakdown","lvl3":""}},
947
+ {"objectID":"86662492401672412d19481d6b54e38149130c9affeb8683bbc2452a3604cd01","title":"telemetry \\<subcommand\\>","url":"/docs/cli/commands#telemetry-subcommand","content":"Telemetry management. Alias: tel. Tracing is configured through LANGFUSE_* environment variables.\n\n`bash","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"telemetry \\<subcommand\\>","lvl3":""}},
948
+ {"objectID":"815edb3c48c4ef94b24238e90b76fdbbbfa8c960a6aab5c399db371e4366d811","title":"Show telemetry status and health","url":"/docs/cli/commands#show-telemetry-status-and-health","content":"npx @juspay/neurolink telemetry status","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Show telemetry status and health","lvl3":""}},
952
949
  {"objectID":"6f45a05852c8f533cb8be0035e8ffefa141b0210e720bc8dcecb21e7eb3dbee5","title":"Flush pending spans to exporters","url":"/docs/cli/commands#flush-pending-spans-to-exporters","content":"npx @juspay/neurolink telemetry flush","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Flush pending spans to exporters","lvl3":""}},
953
- {"objectID":"39fa30a51c78e8f7b5df96d87d57f412a167f762ed4e3267c67771a351a5506b","title":"Show token usage and cost statistics","url":"/docs/cli/commands#show-token-usage-and-cost-statistics","content":"npx @juspay/neurolink telemetry stats --detailed\n\n\n**Subcommands:**\n\n| Subcommand | Aliases | Description |\n| ---------------- | ------------ | ------------------------------------------- |\n| status | | Show exporter status and health |\n| configure | | Configure an exporter with JSON settings |\n| list-exporters | list, ls | List all available and configured exporters |\n| flush | | Flush all pending spans to exporters |\n| stats | | Show token usage and cost statistics |\n\n**Shared flags (all subcommands):**\n\n| Option | Alias | Type | Default | Description |\n| ---------- | ----- | ------- | ------- | -------------------------------------- |\n| --format | -f | string | text | Output format: text, json, table |\n| --quiet | -q | boolean | false | Minimal output |\n\n**configure flags:**\n\n| Option | Alias | Type | Required | Description |\n| ------------ | ----- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------- |\n| --exporter | -e | string | yes | Exporter name: langfuse, langsmith, otel, datadog, sentry, braintrust, arize, posthog, laminar |\n| --config | -c | string | yes | JSON configuration string |\n\n**flush flags:**\n\n| Option | Alias | Type | Default | Description |\n| ----------- | ----- | ------ | ------- | ----------------------- |\n| --timeout | -t | number | 30000 | Timeout in milliseconds |\n\n**stats flags:**\n\n| Option | Alias | Type | Default | Description |\n| --------------- | ----- | ------- | ------- |","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Show token usage and cost statistics","lvl3":""}},
950
+ {"objectID":"39fa30a51c78e8f7b5df96d87d57f412a167f762ed4e3267c67771a351a5506b","title":"Show token usage and cost statistics","url":"/docs/cli/commands#show-token-usage-and-cost-statistics","content":"npx @juspay/neurolink telemetry stats --detailed\n\n\n**Subcommands:**\n\n| Subcommand | Aliases | Description |\n| ---------- | ------- | ------------------------------------ |\n| status | | Show telemetry status and health |\n| flush | | Flush all pending spans |\n| stats | | Show token usage and cost statistics |\n\n**Shared flags (all subcommands):**\n\n| Option | Alias | Type | Default | Description |\n| ---------- | ----- | ------- | ------- | -------------------------------------- |\n| --format | -f | string | text | Output format: text, json, table |\n| --quiet | -q | boolean | false | Minimal output |\n\n**flush flags:**\n\n| Option | Alias | Type | Default | Description |\n| ----------- | ----- | ------ | ------- | ----------------------- |\n| --timeout | -t | number | 30000 | Timeout in milliseconds |\n\n**stats flags:**\n\n| Option | Alias | Type | Default | Description |\n| --------------- | ----- | ------- | ------- | -------------------------- |\n| --detailed | -d | boolean | false | Show detailed statistics |\n| --by-model | -m | boolean | true | Show breakdown by model |\n| --by-provider | -p | boolean | true` | Show breakdown by provider |","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Show token usage and cost statistics","lvl3":""}},
954
951
  {"objectID":"9333c560c0eac410543e0be6a2e9bc9e138016d9cf0b12ade8f25e607220f49e","title":"docs","url":"/docs/cli/commands#docs","content":"Start the NeuroLink documentation MCP server.\n\n`bash","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"docs","lvl3":""}},
955
952
  {"objectID":"e8f772ab075392c0b4ddf2d907da1d9691928dbdc2c4c0961a603f145aec02f3","title":"Start docs server with stdio transport (default)","url":"/docs/cli/commands#start-docs-server-with-stdio-transport-default","content":"npx @juspay/neurolink docs","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Start docs server with stdio transport (default)","lvl3":""}},
956
953
  {"objectID":"2688bf05daed20b355836574a11f3879c32211de4b4d79c87d1da17c01d2f361","title":"Start docs server with HTTP transport on custom port","url":"/docs/cli/commands#start-docs-server-with-http-transport-on-custom-port","content":"npx @juspay/neurolink docs --transport http --port 3001\n\n\n| Option | Alias | Type | Default | Description |\n| ------------- | ----- | ------ | ------- | ------------------------------------------------------ |\n| --transport | -t | string | stdio | Transport protocol: stdio (local) or http (remote) |\n| --port | -p | number | 3001 | Port for HTTP transport (ignored for stdio) |\n\n**Note:** Requires the docs site to be built first (cd docs-site && pnpm build`). The server exposes documentation search and retrieval tools via MCP.","hierarchy":{"lvl0":"Cli","lvl1":"CLI Command Reference","lvl2":"Start docs server with HTTP transport on custom port","lvl3":""}},
@@ -2668,7 +2665,7 @@
2668
2665
  {"objectID":"1006485d87388ff41418394a3fb560c61ee071f5abeb906b07aeaa471d1811ec","title":"All-accounts-exhausted fallback chain","url":"/docs/features/claude-proxy-architecture#all-accounts-exhausted-fallback-chain","content":"When every account is cooling or has failed:\nExplicit fallback chain — From modelRouter.getFallbackChain(). Each entry specifies a provider and model. The request is parsed via parseClaudeRequest() and sent through ctx.neurolink.stream() with maxSteps: 1. Tools, thinking configuration, and conversation history from the original request are passed through to the fallback provider.\nAuto-provider fallback — When no explicit chain is configured, the proxy tries ctx.neurolink.stream() without specifying a provider (uses NeuroLink's default provider). Same options: tools, thinking, and conversation history are included.\nFinal 429 — If all fallbacks fail and rate limiting was seen, returns HTTP 429 with a Retry-After header set to the earliest account recovery time (minimum 1 second, computed from the coolingUntil timestamps).","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy Architecture","lvl2":"All-accounts-exhausted fallback chain","lvl3":""}},
2669
2666
  {"objectID":"6d2e203d9cf8b6cd0c1a0baec39e9bc51f28857834cc5786e71b12d630ed752b","title":"Passthrough streaming (Claude-to-Claude)","url":"/docs/features/claude-proxy-architecture#passthrough-streaming-claude-to-claude","content":"The upstream fetch() response body is a ReadableStream of SSE events from Anthropic. The proxy performs a bootstrap retry: it reads the first chunk from the stream to verify it is non-empty. If the first chunk is empty or the stream ends immediately, the proxy cancels the reader and moves to the next account.\n\nOn a valid first chunk:\nA new ReadableStream is created that enqueues the first chunk in start(), then pulls remaining chunks from the original reader in pull().\nRate-limit headers from Anthropic are forwarded: retry-after, anthropic-ratelimit-requests-remaining, anthropic-ratelimit-requests-limit, anthropic-ratelimit-tokens-remaining, anthropic-ratelimit-tokens-limit.\nThe combined stream is returned as a Response with content-type: text/event-stream.\n\nThe body bytes are never parsed or modified. Claude Code receives exactly what Anthropic sent.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy Architecture","lvl2":"Passthrough streaming (Claude-to-Claude)","lvl3":""}},
2670
2667
  {"objectID":"ae7e99f14c2912be22e0adcb1130ad05876e1b5dbe922f8c7a12436df6907cc3","title":"SSE Stream Interceptor (Telemetry)","url":"/docs/features/claude-proxy-architecture#sse-stream-interceptor-telemetry","content":"In both passthrough and translation paths, the proxy optionally pipes the SSE stream through an SSEInterceptor (sseInterceptor.ts). This is a zero-overhead TransformStream that:\nForwards every byte to the client immediately (no buffering delay).\nParses SSE events in the background to extract: token usage (input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens), model name, content block metadata (text, thinking, tool_use), and stop reason.\nResolves a telemetry promise when the stream ends, providing the extracted data to ProxyRequestTracer for OTel span attributes and metric recording.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy Architecture","lvl2":"SSE Stream Interceptor (Telemetry)","lvl3":""}},
2671
- {"objectID":"2153169143c075dc0727fa1b7c01424cc33726ea81653331073302b5959ab5bc","title":"ProxyRequestTracer (OTel Spans)","url":"/docs/features/claude-proxy-architecture#proxyrequesttracer-otel-spans","content":"ProxyRequestTracer (proxyTracer.ts) manages the OTel span lifecycle for each proxy request:\nRequest span: Created at request receive, covers the full request lifecycle.\nUpstream spans: One per retry attempt, tracks fetch duration and response status.\nUsage attributes: Token counts, model, provider, cost estimate, rate-limit headers.\nCorrelation: Writes traceId and spanId into the request log entry for cross-signal correlation.\n\nThe tracer emits metrics via TelemetryService: request counters, retry counters, latency histograms, request/response body sizes, estimated cost, cache token counters, and model-substitution counters when the translated response model differs from the requested one.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy Architecture","lvl2":"ProxyRequestTracer (OTel Spans)","lvl3":""}},
2668
+ {"objectID":"2153169143c075dc0727fa1b7c01424cc33726ea81653331073302b5959ab5bc","title":"ProxyRequestTracer (OTel Spans)","url":"/docs/features/claude-proxy-architecture#proxyrequesttracer-otel-spans","content":"ProxyRequestTracer (proxyTracer.ts) manages the OTel span lifecycle for each proxy request:\nRequest span: Created at request receive, covers the full request lifecycle.\nUpstream spans: One per retry attempt, tracks fetch duration and response status.\nUsage attributes: Token counts, model, provider, cost estimate, rate-limit headers.\nCorrelation: Writes traceId and spanId into the request log entry for cross-signal correlation.\n\nThe tracer emits OpenTelemetry metrics: request counters, retry counters, latency histograms, request/response body sizes, estimated cost, cache token counters, and model-substitution counters when the translated response model differs from the requested one.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy Architecture","lvl2":"ProxyRequestTracer (OTel Spans)","lvl3":""}},
2672
2669
  {"objectID":"85b169919f86b2b781957a6c52742f1f319efaed12bc819b797231f10171162a","title":"Translation streaming (Claude-to-Other)","url":"/docs/features/claude-proxy-architecture#translation-streaming-claude-to-other","content":"When the target is a non-Anthropic provider:\nThe Claude request is parsed into NeuroLink format via parseClaudeRequest().\nctx.neurolink.stream() produces a NeuroLink stream result.\nA ClaudeStreamSerializer (from claudeFormat.ts) converts NeuroLink stream chunks into Anthropic SSE frames.\nAn async generator yields SSE frames: serializer.start() → serializer.pushDelta(text) for each chunk → serializer.finish().\nSSE keep-alive comments (: keep-alive\\n\\n) are emitted every 15 seconds during idle periods.","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy Architecture","lvl2":"Translation streaming (Claude-to-Other)","lvl3":""}},
2673
2670
  {"objectID":"ec5736ae6e6220fadefe732481beb0cb1829adb22c3cd4112bc87745b01829ca","title":"Response handling in proxy.ts","url":"/docs/features/claude-proxy-architecture#response-handling-in-proxyts","content":"The Hono handler in proxy.ts handles three return types from route handlers:\nResponse object — Returned directly (passthrough streaming).\nAsyncIterable<string> — Wrapped in a ReadableStream and returned with SSE headers (translation streaming).\nObject with httpStatus — Returned as JSON with that status code.\nObject with type: \"error\" — Status mapped via mapClaudeErrorTypeToStatus().","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy Architecture","lvl2":"Response handling in proxy.ts","lvl3":""}},
2674
2671
  {"objectID":"b0c4fa082c940e5de41c540d155ff30fde37668536355372a0278f2780c1a5be","title":"6. OAuth Cloaking (oauthFetch.ts)","url":"/docs/features/claude-proxy-architecture#6-oauth-cloaking-oauthfetchts","content":"Important: The proxy passthrough path does NOT use createOAuthFetch(). It uses plain fetch() with manually constructed headers (client headers forwarded, auth overridden, oauth beta ensured). The oauthFetch.ts module is used only by the direct NeuroLink Anthropic provider for SDK usage.\n\ncreateOAuthFetch() is a factory that returns a custom fetch function. It has two modes controlled by the skipBodyTransform parameter:","hierarchy":{"lvl0":"Features","lvl1":"Claude Proxy Architecture","lvl2":"6. OAuth Cloaking (oauthFetch.ts)","lvl3":""}},
@@ -3965,38 +3962,29 @@
3965
3962
  {"objectID":"d6ae12d83a1d4ac329230b324df41139e12e69cc6b9716c9a488474f68a92e56","title":"Example 2: Document Comparison","url":"/docs/features/multimodal#example-2-document-comparison","content":"Compare two versions of a contract:","hierarchy":{"lvl0":"Features","lvl1":"Multimodal Capabilities Guide","lvl2":"Example 2: Document Comparison","lvl3":""}},
3966
3963
  {"objectID":"4efaf71953966b0390225a95bede8ba98ba13fc231e459aa3caff383bfe0d214","title":"Example 3: Data Visualization Analysis","url":"/docs/features/multimodal#example-3-data-visualization-analysis","content":"Analyze charts and underlying data together:","hierarchy":{"lvl0":"Features","lvl1":"Multimodal Capabilities Guide","lvl2":"Example 3: Data Visualization Analysis","lvl3":""}},
3967
3964
  {"objectID":"dc35015c48cf20bf4abe2a50399f0f6c0a87119e86f614f784bd9233318b779f","title":"Summary","url":"/docs/features/multimodal#summary","content":"NeuroLink's multimodal capabilities provide:\n\n✅ Universal input support - Images, PDFs, CSV files\n✅ Provider flexibility - Extensive provider compatibility matrix\n✅ Automatic format detection - Smart file type recognition\n✅ Accessibility features - Alt text support for images\n✅ Production-ready - Battle-tested at enterprise scale\n✅ Developer-friendly - Works seamlessly across CLI and SDK\n\nNext Steps:\nReview the provider support matrix to select the right provider\nTry the quick start examples with your use case\nExplore advanced recipes for complex scenarios\nCheck troubleshooting if you encounter issues","hierarchy":{"lvl0":"Features","lvl1":"Multimodal Capabilities Guide","lvl2":"Summary","lvl3":""}},
3968
- {"objectID":"c56b41cb0c1e8e9dfc542fc3c18cf1024985a68cd588c7616a5facff77a7613a","title":"Observability Guide","url":"/docs/features/observability","content":"Observability Guide\n\nEnterprise-grade observability for AI operations with Langfuse and OpenTelemetry integration.\n\nOverview\n\nNeuroLink provides comprehensive observability features for monitoring AI operations in production:\nLangfuse Integration: LLM-specific observability with token tracking, cost analysis, and trace visualization\nOpenTelemetry Support: Standard distributed tracing compatible with Jaeger, Zipkin, and other backends\nExternal Provider Mode: Integrate with existing OpenTelemetry instrumentation without conflicts\nContext Propagation: Automatic context enrichment with user, session, and custom metadata\n\nFor the Claude proxy's local OpenObserve stack and maintained dashboard, use Claude Proxy and Claude Proxy Observability. Those guides cover neurolink proxy telemetry setup, dashboard import, stream names, and how to interpret proxy-specific logs, metrics, and traces.\n\nQuick Start\n\nBasic Langfuse Setup\n\nEnvironment Variables\n\nContext Management\n\nSetting Context\n\nUse setLangfuseContext to attach metadata to all spans in an async context:\n\nContext Fields\n\n| Field | Purpose |\n| ---------------- | ------------------------------------------ |\n| userId | Identify the user for per-user analytics |\n| sessionId | Group traces within a user session |\n| conversationId | Group traces in a conversation thread |\n| requestId | Correlate with application logs |\n| traceName | Custom name in Langfuse UI |\n| metadata | Key-value pairs for filtering and analysis |\n\nReading Context\n\nOperation Name Support\n\nNeuroLink automatically detects operation names from AI SDK spans and includes them in trace names for better observability. This provides immediate visibility into what type of AI operation is being performed.\n\nOperation Name Configuration\n\nBy default, NeuroLink automatically detects operation names from:\nVercel AI SDK spans: Spans starting with ai. (e.g., ai.streamText, ai.generateText, ai.embed)\nOpenTelemetry GenAI conventions: Standard semantic convention operations (chat, embeddings, text_completion)\n\nWhen auto-detection is enabled, traces automatically include the detected operation:\nA generateText call becomes: user@email.com:ai.generateText\nA streamText call becomes: user@email.com:ai.streamText\nAn embedding call becomes: user@email.com:embeddings\n\nTrace Name Formats\n\nControl how trace names are constructed using the traceNameFormat option:\n\n| Format | Example Output | Description |\n| ------------------------ | ------------------------------ | --------------------------- |\n| \"userId:operationName\" | user@email.com:ai.streamText | Default format, user first |\n| \"operationName:userId\" | ai.streamText:user@email.com | Operation first |\n| \"operationName\" | ai.streamText | Operation only |\n| \"userId\" | user@email.com | User only (legacy behavior) |\n| Custom function | Custom output | Full control over format |\n\nCustom Format Function\n\nFor full control over trace naming, provide a custom function:\n\nContext-Level Configuration\n\nOverride operation name behavior at the context level:\n\nBackward Compatibility\n\nOperation name support is fully backward compatible:\nExplicit traceName takes priority: If you set traceName in context, it always overrides auto-detected names:\nDisable for legacy behavior: Set autoDetectOperationName: false to restore previous behavior:\nExisting code works unchanged: Code using traceName continues to work exactly as before:\n\n \n\nPriority Order\n\nWhen determining the trace name, NeuroLink follows this priority order:\nExplicit traceName in context (highest priority)\nExplicit operationName in context + userId (formatted per traceNameFormat)\nAuto-detected operation name from span + userId (if autoDetectOperationName is enabled)\nuserId only (fallback)\n\nWrapper Span Support\n\nWhen host applications create wrapper spans (trace-root spans) before AI operations, the standard auto-detection in onStart() fails because the AI SDK span does not exist yet at wrapper span creation time.\n\nThe Problem:\n\nAt the time the wrapper span starts, there is no AI SDK span to detect the operation from, so the trace name would only include the userId.\n\nThe Solution:\n\nNeuroLink automatically handles this by detecting operations from child spans and updating the trace name when the wrapper span ends:\nWrapper span starts - onStart() sets traceName to just userId (e.g., user-123)\nAI SDK span starts - onStart() detects ai.streamText and stores operation in a map keyed by traceId\nWrapper span ends - onEnd() looks up the stored operation and updates traceName to user-123:ai.streamText\n\nThis behavior is automatic and requires no code changes in host applications. The trace name in Langfuse will correctly include both the userId and the detected operation name.\n","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"","lvl3":""}},
3969
- {"objectID":"db6cc880d3b187c65a71c44dcdf928120d86ca14ee034da45f5dd218dcac59b5","title":"Observability Guide","url":"/docs/features/observability#observability-guide","content":"Enterprise-grade observability for AI operations with Langfuse and OpenTelemetry integration.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Observability Guide","lvl3":""}},
3970
- {"objectID":"6dd068b5a05003f273d4814560c2aab4d2e80c7ded42e841b4295e2b811a65e5","title":"Overview","url":"/docs/features/observability#overview","content":"NeuroLink provides comprehensive observability features for monitoring AI operations in production:\nLangfuse Integration: LLM-specific observability with token tracking, cost analysis, and trace visualization\nOpenTelemetry Support: Standard distributed tracing compatible with Jaeger, Zipkin, and other backends\nExternal Provider Mode: Integrate with existing OpenTelemetry instrumentation without conflicts\nContext Propagation: Automatic context enrichment with user, session, and custom metadata\n\nFor the Claude proxy's local OpenObserve stack and maintained dashboard, use Claude Proxy and Claude Proxy Observability. Those guides cover neurolink proxy telemetry setup, dashboard import, stream names, and how to interpret proxy-specific logs, metrics, and traces.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Overview","lvl3":""}},
3971
- {"objectID":"f5b277d3ae78e90affc7f614bbe8f4ea0e076874c57d77d204bd0764d0952622","title":"Environment Variables","url":"/docs/features/observability#environment-variables","content":"`bash","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Environment Variables","lvl3":""}},
3972
- {"objectID":"e282cefcd21de2af047fc4d4a88d29eea980c9cbdef0a72b4526cdf0e2ce0170","title":"Langfuse credentials","url":"/docs/features/observability#langfuse-credentials","content":"LANGFUSEPUBLICKEY=pk-lf-...\nLANGFUSESECRETKEY=sk-lf-...\nLANGFUSEBASEURL=https://cloud.langfuse.com # or self-hosted","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Langfuse credentials","lvl3":""}},
3973
- {"objectID":"f106fb2f59d571149ec64cb1a8c0cc5086f99d98fee77d5b9f56a838c1144284","title":"Optional defaults","url":"/docs/features/observability#optional-defaults","content":"LANGFUSE_ENVIRONMENT=production\nLANGFUSE_RELEASE=1.0.0","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Optional defaults","lvl3":""}},
3974
- {"objectID":"88c92784744e5dd73ef59159dade30855280e6c98407b596a484e4ed5c25822d","title":"spans; anything over it is trimmed to valid JSON, keeping the user's question.","url":"/docs/features/observability#spans-anything-over-it-is-trimmed-to-valid-json-keeping-the-users-question","content":"NEUROLINKSPANATTRIBUTEMAXCHARS=40000\n`","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"spans; anything over it is trimmed to valid JSON, keeping the user's question.","lvl3":""}},
3975
- {"objectID":"2e424a89666870b887e95be2075dc80aba5d9a635c4b711aaadce25b776d8654","title":"Setting Context","url":"/docs/features/observability#setting-context","content":"Use setLangfuseContext to attach metadata to all spans in an async context:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Setting Context","lvl3":""}},
3976
- {"objectID":"a5d647d37c18f927e33ff9a3146d65deaffe05ebab47410e85b5615e47e2d4df","title":"Context Fields","url":"/docs/features/observability#context-fields","content":"| Field | Purpose |\n| ---------------- | ------------------------------------------ |\n| userId | Identify the user for per-user analytics |\n| sessionId | Group traces within a user session |\n| conversationId | Group traces in a conversation thread |\n| requestId | Correlate with application logs |\n| traceName | Custom name in Langfuse UI |\n| metadata | Key-value pairs for filtering and analysis |","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Context Fields","lvl3":""}},
3977
- {"objectID":"89f1a2e53dff482b3f106f6bc884a5928996cd4458b2881f87bf70065edc3d3a","title":"Operation Name Support","url":"/docs/features/observability#operation-name-support","content":"NeuroLink automatically detects operation names from AI SDK spans and includes them in trace names for better observability. This provides immediate visibility into what type of AI operation is being performed.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Operation Name Support","lvl3":""}},
3978
- {"objectID":"444800daaa6e78cbb71bf613f08b530c1d568037cfea7cb0f4f064ad21567710","title":"Operation Name Configuration","url":"/docs/features/observability#operation-name-configuration","content":"By default, NeuroLink automatically detects operation names from:\nVercel AI SDK spans: Spans starting with ai. (e.g., ai.streamText, ai.generateText, ai.embed)\nOpenTelemetry GenAI conventions: Standard semantic convention operations (chat, embeddings, text_completion)\n\nWhen auto-detection is enabled, traces automatically include the detected operation:\nA generateText call becomes: user@email.com:ai.generateText\nA streamText call becomes: user@email.com:ai.streamText\nAn embedding call becomes: user@email.com:embeddings","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Operation Name Configuration","lvl3":""}},
3979
- {"objectID":"ef26840facfb00c6e1b7131cb365037a018193c3d69b80a3aebf2c6ec52df706","title":"Trace Name Formats","url":"/docs/features/observability#trace-name-formats","content":"Control how trace names are constructed using the traceNameFormat option:\n\n| Format | Example Output | Description |\n| ------------------------ | ------------------------------ | --------------------------- |\n| \"userId:operationName\" | user@email.com:ai.streamText | Default format, user first |\n| \"operationName:userId\" | ai.streamText:user@email.com | Operation first |\n| \"operationName\" | ai.streamText | Operation only |\n| \"userId\" | user@email.com | User only (legacy behavior) |\n| Custom function | Custom output | Full control over format |","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Trace Name Formats","lvl3":""}},
3980
- {"objectID":"94afb630fde08ac47f9287f117b197736b1004cb92d1fe99c6e26539aaf7459c","title":"Custom Format Function","url":"/docs/features/observability#custom-format-function","content":"For full control over trace naming, provide a custom function:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Custom Format Function","lvl3":""}},
3981
- {"objectID":"38762ce452dbbc2cf45f7315f8f1365a49c687578a5fcf062e7269ac849586b0","title":"Context-Level Configuration","url":"/docs/features/observability#context-level-configuration","content":"Override operation name behavior at the context level:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Context-Level Configuration","lvl3":""}},
3982
- {"objectID":"7358e6a7cdc3a923c028bace2d0ed4b4e8d481dfb489ae07ea9346724579b9b0","title":"Backward Compatibility","url":"/docs/features/observability#backward-compatibility","content":"Operation name support is fully backward compatible:\nExplicit traceName takes priority: If you set traceName in context, it always overrides auto-detected names:\nDisable for legacy behavior: Set autoDetectOperationName: false to restore previous behavior:\nExisting code works unchanged: Code using traceName continues to work exactly as before:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Backward Compatibility","lvl3":""}},
3983
- {"objectID":"4f9008605b82988f7d6c41054fd9614045f9cb020b085fff7c59d72d144f56a1","title":"Priority Order","url":"/docs/features/observability#priority-order","content":"When determining the trace name, NeuroLink follows this priority order:\nExplicit traceName in context (highest priority)\nExplicit operationName in context + userId (formatted per traceNameFormat)\nAuto-detected operation name from span + userId (if autoDetectOperationName is enabled)\nuserId only (fallback)","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Priority Order","lvl3":""}},
3984
- {"objectID":"c181746ef1554ef0c3750f45413e3e69df75682343c7ea3d44d8677e62204841","title":"Wrapper Span Support","url":"/docs/features/observability#wrapper-span-support","content":"When host applications create wrapper spans (trace-root spans) before AI operations, the standard auto-detection in onStart() fails because the AI SDK span does not exist yet at wrapper span creation time.\n\nThe Problem:\n\nAt the time the wrapper span starts, there is no AI SDK span to detect the operation from, so the trace name would only include the userId.\n\nThe Solution:\n\nNeuroLink automatically handles this by detecting operations from child spans and updating the trace name when the wrapper span ends:\nWrapper span starts - onStart() sets traceName to just userId (e.g., user-123)\nAI SDK span starts - onStart() detects ai.streamText and stores operation in a map keyed by traceId\nWrapper span ends - onEnd() looks up the stored operation and updates traceName to user-123:ai.streamText\n\nThis behavior is automatic and requires no code changes in host applications. The trace name in Langfuse will correctly include both the userId and the detected operation name.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Wrapper Span Support","lvl3":""}},
3985
- {"objectID":"272fa5a373b3d7f7f62fdf284f826e44201de7f839a5f35d18ea7ca42fff8331","title":"Custom Spans","url":"/docs/features/observability#custom-spans","content":"Create custom spans for detailed tracing:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Custom Spans","lvl3":""}},
3986
- {"objectID":"0436097dc65232bef8573065b634e027f27357dc6b640fad27d07059b99c0d8e","title":"Proxy Observability","url":"/docs/features/observability#proxy-observability","content":"The NeuroLink proxy automatically initializes OpenTelemetry and exports three signal types (traces, metrics, logs) via OTLP HTTP when OTEL_EXPORTER_OTLP_ENDPOINT is set. Each proxy request creates an OTel span with token usage, model, cost, and rate-limit attributes. Request log entries include traceId and spanId for cross-signal correlation. See the Telemetry Guide for details.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Proxy Observability","lvl3":""}},
3987
- {"objectID":"52455a0baa00ba69d2784e611d528761b66b992d4e8f4f07cfbf3e3485c0d259","title":"External TracerProvider Mode","url":"/docs/features/observability#external-tracerprovider-mode","content":"If your application already has OpenTelemetry instrumentation (e.g., for HTTP, database tracing), use external provider mode to avoid \"duplicate registration\" errors. Note: TelemetryService now automatically detects and reuses an existing global TracerProvider, so in many cases you no longer need explicit external provider configuration.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"External TracerProvider Mode","lvl3":""}},
3988
- {"objectID":"5faed81739f8284d2b05803ff55c6238ec61e844a74329aafab52889b2fa3740","title":"Auto-Detection Mode","url":"/docs/features/observability#auto-detection-mode","content":"Alternatively, let NeuroLink auto-detect external providers:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Auto-Detection Mode","lvl3":""}},
3989
- {"objectID":"4c5428e951f51882af5c19ae80b061a8742ff015fc4e2b5824d9d07ea38abcf3","title":"Available Exports","url":"/docs/features/observability#available-exports","content":"| Export | Description |\n| --------------------------------- | -------------------------------------------------- |\n| getSpanProcessors() | Returns [ContextEnricher, LangfuseSpanProcessor] |\n| createContextEnricher() | Factory for creating ContextEnricher instances |\n| isUsingExternalTracerProvider() | Check if in external provider mode |\n| getLangfuseSpanProcessor() | Get the LangfuseSpanProcessor directly |\n| getTracerProvider() | Get the TracerProvider (null in external mode) |","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Available Exports","lvl3":""}},
3990
- {"objectID":"b3769360b9e9f1595bd53c4670c476e4b4cae4d7683ae076aa27d0e41464d800","title":"Vercel AI SDK Integration","url":"/docs/features/observability#vercel-ai-sdk-integration","content":"If your application also uses the Vercel AI SDK, NeuroLink's ContextEnricher reads the GenAI semantic-convention attributes that experimental_telemetry emits. NeuroLink itself has no dependency on the ai package — the imports below are your application's, and the SDK is not required to use NeuroLink:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Vercel AI SDK Integration","lvl3":""}},
3991
- {"objectID":"e22d1f512a3169b7d13a218546943fffbe953ac7966112042f510a0fc1169792","title":"Captured Attributes","url":"/docs/features/observability#captured-attributes","content":"The ContextEnricher automatically reads these GenAI attributes:\ngen_ai.system - AI provider (openai, anthropic, etc.)\ngen_ai.request.model - Model requested\ngen_ai.usage.input_tokens - Input tokens used\ngen_ai.usage.output_tokens - Output tokens used\nai.finishReason - Why generation finished","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Captured Attributes","lvl3":""}},
3992
- {"objectID":"ff249f5607836c5851106d0599eb6fd65e753e6c642790dca9139f1bee01bb28","title":"Health Monitoring","url":"/docs/features/observability#health-monitoring","content":"Check Langfuse health status:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Health Monitoring","lvl3":""}},
3993
- {"objectID":"e21ecc4b18e02f6fe02f1f92255cf39a24ba14a73f982d32e75192d7e4a60aa8","title":"Flushing and Shutdown","url":"/docs/features/observability#flushing-and-shutdown","content":"Ensure all spans are sent before process exit:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Flushing and Shutdown","lvl3":""}},
3994
- {"objectID":"7157c25b1141b9c5c026e7ee815af42488371e1d5d9b9ae69d18160c30eea7d4","title":"Empty span processors from getSpanProcessors()","url":"/docs/features/observability#empty-span-processors-from-getspanprocessors","content":"Problem: getSpanProcessors() returns an empty array.\n\nSolution: Ensure NeuroLink is initialized before calling getSpanProcessors():","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Empty span processors from getSpanProcessors()","lvl3":""}},
3995
- {"objectID":"bc71261bdfe2ae52e4e986773e7a1ab8a1583a552366ae62a157993d695cd1a7","title":"Context not appearing in Langfuse traces","url":"/docs/features/observability#context-not-appearing-in-langfuse-traces","content":"Problem: userId, sessionId, or other context fields don't appear in Langfuse.\n\nSolution: Ensure setLangfuseContext is called in the same async context as your AI operations:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Context not appearing in Langfuse traces","lvl3":""}},
3996
- {"objectID":"021987687a6713a489df5e9e114688a0927de816994378392a8f77808d451352","title":"Duplicate TracerProvider registration errors","url":"/docs/features/observability#duplicate-tracerprovider-registration-errors","content":"Problem: Error like \"TracerProvider already registered\" or \"duplicate registration\".\n\nSolution: Set useExternalTracerProvider: true in your config:","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Duplicate TracerProvider registration errors","lvl3":""}},
3997
- {"objectID":"534fbec3fbb29aa94fe464858c0906946aa7d909f9fa82dd2cc4c1f8d6821027","title":"Spans not being sent to Langfuse","url":"/docs/features/observability#spans-not-being-sent-to-langfuse","content":"Problem: Traces don't appear in Langfuse dashboard.\n\nSolution:\nVerify credentials are correct\nCheck health status:\nEnsure flushOpenTelemetry() is called before process exit\nCheck network connectivity to Langfuse endpoint","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Spans not being sent to Langfuse","lvl3":""}},
3998
- {"objectID":"bc1755900c005626bd213860a41c0169833cf8288e799f4cb83e4ee499aa9396","title":"API Reference","url":"/docs/features/observability#api-reference","content":"The following functions and types are exported from @juspay/neurolink:\n\nFunctions:\nsetLangfuseContext - Set context for Langfuse traces\ngetLangfuseContext - Get current Langfuse context\ngetTracer - Get OpenTelemetry tracer instance\ngetSpanProcessors - Get span processors for external TracerProvider integration\n\nTypes:\nLangfuseConfig - Configuration options for Langfuse integration\nLangfuseSpanAttributes - GenAI semantic convention attributes","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"API Reference","lvl3":""}},
3999
- {"objectID":"9a2c99612604332f4b2bc32fb673fe19412249aba74ad41f2ed2cfd84a8d1185","title":"See Also","url":"/docs/features/observability#see-also","content":"Telemetry Guide - OpenTelemetry setup with Jaeger\nEnterprise Monitoring - Prometheus and Grafana setup\nAnalytics Reference - Token and cost tracking","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"See Also","lvl3":""}},
3965
+ {"objectID":"c56b41cb0c1e8e9dfc542fc3c18cf1024985a68cd588c7616a5facff77a7613a","title":"Observability Guide","url":"/docs/features/observability","content":"Observability Guide\n\nNeuroLink exports every AI operation to Langfuse. Setup is environment variables only.\n\nArchitecture\n\nOne instrumentation feeds every backend:\n\nNeuroLink's own provider uses this pipeline, with LangfuseExporter registered when Langfuse is enabled. The Langfuse exporter queues spans without blocking the caller and posts them in batches to Langfuse's OTLP endpoint (POST /api/public/otel/v1/traces, OTLP/HTTP JSON, Basic auth with your keys). Spans that are not observations (health checks, auth, middleware) are skipped, and their children are re-parented onto the nearest exported ancestor so the tree stays connected.\n\nWarning: full input and output are captured by default. Prompts, system prompts, tool arguments, tool results and model output are sent to Langfuse as they are. If your data is sensitive, set mask before enabling tracing. See Masking sensitive data.\n\nWarning: tracing turns on automatically. If LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY are present in the environment, NeuroLink starts exporting with no code change. Upgrading with those variables already set starts sending data. Set observability: { langfuse: false } to opt out.\n\nSetup\n\nEnvironment variables\n\n| Variable | Purpose |\n| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| LANGFUSE_PUBLIC_KEY | Langfuse public key (required to auto-enable) |\n| LANGFUSE_SECRET_KEY | Langfuse secret key (required to auto-enable) |\n| LANGFUSE_BASE_URL | Langfuse host; defaults to Langfuse Cloud |\n| LANGFUSE_TRACING_ENVIRONMENT | Environment label on every trace |\n| LANGFUSE_RELEASE | Release label on every trace |\n| OTEL_EXPORTER_OTLP_ENDPOINT | Also export traces and metrics to an OTLP collector |\n| NEUROLINK_SPAN_ATTRIBUTE_MAX_CHARS | Largest serialized span input, output or tool payload in characters (default 40000, minimum 10000). Anything over it is trimmed to valid JSON, keeping the user's question, then this turn's newest messages, then history |\n\nDisable or override\n\nEvery field is optional and falls back to its LANGFUSE_* variable. The type is NeurolinkLangfuseConfig.\n\n| Field | Meaning |\n| --------------- | ------------------------------------------------------------ |\n| publicKey | Langfuse public key |\n| secretKey | Langfuse secret key |\n| baseUrl | Langfuse host |\n| environment | Environment label |\n| release | Release label |\n| mask | Function applied to input, output and metadata before export |\n| exportMode | \"batched\" (default) or \"immediate\" |\n| flushAt | Spans buffered before a batch is sent (default 15) |\n| flushInterval | Seconds between batch flushes (default 5) |\n\nPer-call context\n\nPass context on generate, stream and decide. The values are attached to every span the call creates, including tool calls and fallback attempts, so one call is one trace.\n\n| Field | Recorded as |\n| ----------------- | -------------------------------------------------------","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"","lvl3":""}},
3966
+ {"objectID":"db6cc880d3b187c65a71c44dcdf928120d86ca14ee034da45f5dd218dcac59b5","title":"Observability Guide","url":"/docs/features/observability#observability-guide","content":"NeuroLink exports every AI operation to Langfuse. Setup is environment variables only.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Observability Guide","lvl3":""}},
3967
+ {"objectID":"f66991b3ca536e199e647a4e425060cf8af3be12b320be25230f3fe79a3cf66c","title":"Architecture","url":"/docs/features/observability#architecture","content":"One instrumentation feeds every backend:\n\nNeuroLink's own provider uses this pipeline, with LangfuseExporter registered when Langfuse is enabled. The Langfuse exporter queues spans without blocking the caller and posts them in batches to Langfuse's OTLP endpoint (POST /api/public/otel/v1/traces, OTLP/HTTP JSON, Basic auth with your keys). Spans that are not observations (health checks, auth, middleware) are skipped, and their children are re-parented onto the nearest exported ancestor so the tree stays connected.\n\nWarning: full input and output are captured by default. Prompts, system prompts, tool arguments, tool results and model output are sent to Langfuse as they are. If your data is sensitive, set mask before enabling tracing. See Masking sensitive data.\n\nWarning: tracing turns on automatically. If LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY are present in the environment, NeuroLink starts exporting with no code change. Upgrading with those variables already set starts sending data. Set observability: { langfuse: false } to opt out.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Architecture","lvl3":""}},
3968
+ {"objectID":"f5b277d3ae78e90affc7f614bbe8f4ea0e076874c57d77d204bd0764d0952622","title":"Environment variables","url":"/docs/features/observability#environment-variables","content":"| Variable | Purpose |\n| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| LANGFUSE_PUBLIC_KEY | Langfuse public key (required to auto-enable) |\n| LANGFUSE_SECRET_KEY | Langfuse secret key (required to auto-enable) |\n| LANGFUSE_BASE_URL | Langfuse host; defaults to Langfuse Cloud |\n| LANGFUSE_TRACING_ENVIRONMENT | Environment label on every trace |\n| LANGFUSE_RELEASE | Release label on every trace |\n| OTEL_EXPORTER_OTLP_ENDPOINT | Also export traces and metrics to an OTLP collector","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Environment variables","lvl3":""}},
3969
+ {"objectID":"304f3b3f1d3d11c91945e49e4ae3f60d2b9a826b87a3948f18fd137a16b38c45","title":"Disable or override","url":"/docs/features/observability#disable-or-override","content":"Every field is optional and falls back to its LANGFUSE_* variable. The type is NeurolinkLangfuseConfig.\n\n| Field | Meaning |\n| --------------- | ------------------------------------------------------------ |\n| publicKey | Langfuse public key |\n| secretKey | Langfuse secret key |\n| baseUrl | Langfuse host |\n| environment | Environment label |\n| release | Release label |\n| mask | Function applied to input, output and metadata before export |\n| exportMode | \"batched\" (default) or \"immediate\" |\n| flushAt | Spans buffered before a batch is sent (default 15) |\n| flushInterval | Seconds between batch flushes (default 5) |","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Disable or override","lvl3":""}},
3970
+ {"objectID":"d5c2e109ca689299bbc1e1068341dfd6ba1294b1ee3c11cebe6489977865892e","title":"Per-call context","url":"/docs/features/observability#per-call-context","content":"Pass context on generate, stream and decide. The values are attached to every span the call creates, including tool calls and fallback attempts, so one call is one trace.\n\n| Field | Recorded as |\n| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |\n| userId | Trace user |\n| sessionId | Trace session |\n| tags | Trace tags |\n| traceName | Trace name |\n| conversationId | Metadata key conversationId |\n| requestId | Metadata key requestId |\n| metadata | Metadata; values up to 200 characters are on every observation, longer values and arrays are recorded in full on the trace only |\n| observationName | Name of the root observation of this call; default generate or stream; not propagated to child observations or used as the trace name |","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Per-call context","lvl3":""}},
3971
+ {"objectID":"d262ba0787c1b57c76e303845fc9c6f447a3a2f747a880270f15c61fcc1863bb","title":"setLangfuseContext","url":"/docs/features/observability#setlangfusecontext","content":"Wrap your own code to attach the same attributes to everything inside it, including spans you create yourself.\n\nsetLangfuseContext(params: NeurolinkTraceContext, fn) returns whatever fn returns. It is a thin wrapper over Langfuse's propagateAttributes.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"setLangfuseContext","lvl3":""}},
3972
+ {"objectID":"542eff7388511fe18f61b3de966dff32a0a0ccfa5c95df170298790e0233739d","title":"Naming","url":"/docs/features/observability#naming","content":"No span name, attribute key or metadata key contains the product name. Names never carry per-execution values: the model and provider are fields, the step number is metadata.\n\n| Observation | Name | Langfuse type | Parent |\n| -------------------------- | ------------------------------------- | ------------- | ---------------------- |\n| generate / stream call | generate / stream | agent | none (trace root) |\n| Fallback attempt | generate.attempt / stream.attempt | span | root |\n| Agent loop step | step (step_index metadata) | span | the attempt span |\n| One model request | generate / stream | generation | its step |\n| Tool execution | the tool's name, e.g. get_weather | tool | the step that ran it |\n| decide | decide | generation | caller or root |\n\nA model request is named after the API the caller used (NeuroLink.generate or provider.generate gives generate, NeuroLink.stream or provider.stream gives stream). Its model is the observation's model field (the model the provider reported, falling back to the requested one) and the provider id is the provider metadata key.\n\nThe trace name is context.traceName when given, otherwise the operation name (generate, stream). An outer setLangfuseContext takes precedence over per-call context for user, session and trace name.\n\nEmbeddings, RAG, workflow, evaluation, transcribe, TTS and media tracing are not yet recorded. The root also sets trace-level input and output; a generate or stream nested inside another turn does not.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Naming","lvl3":""}},
3973
+ {"objectID":"ceb0e84f71b6a9deb6a57e236efa009236e933eb892ad569d59e36ba873292f3","title":"Steps and chat format","url":"/docs/features/observability#steps-and-chat-format","content":"Each iteration of the agent loop gets one step span with its one-based index in the step_index metadata. It parents that iteration's generation and the tool observations the model requested in it, so a multi-tool turn reads as step 1 (call, tools), step 2 (call, tools), and so on.\n\nGeneration input is a chat message array with the system message first. Generation output is an assistant message array: content, plus reasoning and tool_calls ({ id, type: \"function\", function: { name, arguments } }) when present. Langfuse renders both as a conversation.\n\nGeneration details:\nUsage includes input, output, total, cache read, cache creation and reasoning tokens, whatever naming the provider uses.\nCost is computed from NeuroLink's pricing table and recorded as costDetails.total.\nModel parameters are temperature, max tokens, top-p and thinking level.\nTime to first token is recorded as the generation's completion start time for streams.\nLevel is WARNING for a length or content-filter finish, an aborted call, an early break out of a stream, or an empty output, and ERROR when the call throws.\nStreams end their spans when the stream finishes, is abandoned or is aborted.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Steps and chat format","lvl3":""}},
3974
+ {"objectID":"7dbc08e9d130f6a8e970396c854cb6afb0be27558cdbaa21122d1df517e4006a","title":"Masking sensitive data","url":"/docs/features/observability#masking-sensitive-data","content":"mask runs on span input and output before export. It receives { data } and returns the value to send.\n\nmask also runs on trace and observation metadata. If it throws, the value is replaced by <fully masked>. Provider credentials are already redacted from recorded values. Everything else is captured as is.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Masking sensitive data","lvl3":""}},
3975
+ {"objectID":"bc90fcd87977756303a1a998fc869c12bbd8ef1f1b88e4f17746e4bd4463d15f","title":"Langfuse exporter behaviour","url":"/docs/features/observability#langfuse-exporter-behaviour","content":"Endpoint. POST {baseUrl}/api/public/otel/v1/traces as OTLP/HTTP JSON. Requests are cut at 500 spans or 3.5 MB.\nObservation types. Agent, generation, tool, step, attempt and the other observation types reach Langfuse with their native type, model, parameters, usage, cost and first-token time.\nIdentity. User, session, trace name, tags and trace metadata are set on every observation, not only the root.\nEnvironment and release. The config field, then LANGFUSE_TRACING_ENVIRONMENT / LANGFUSE_RELEASE; they fill spans that do not carry them already.\nBatching. Spans are sent when flushAt spans are queued, every flushInterval seconds, on flushOpenTelemetry() and on shutdown. exportMode: \"immediate\" sends each span as it ends.\nFailures. A request that fails with 429, 5xx or a network error is retried with exponential backoff. Other 4xx responses are not retried. Spans Langfuse reports as rejected (partialSuccess) are logged once as a warning and not re-sent. A 401 or 403 logs one warning per process (\"Langfuse credentials rejected\") and is not retried. Delivery never throws into your code.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Langfuse exporter behaviour","lvl3":""}},
3976
+ {"objectID":"ba32010e859f5101a6247151e93a3db0fdaa79d0afe2d47c1492c74a0e04f5f5","title":"External OpenTelemetry provider","url":"/docs/features/observability#external-opentelemetry-provider","content":"If your application registers its own global TracerProvider, NeuroLink creates no provider. Other backends: add that vendor's span processor to your provider, or set OTEL_EXPORTER_OTLP_ENDPOINT. For Langfuse choose one of two recipes.\n\n(a) Exporter pipeline (recommended). Add createExporterSpanProcessor() to your provider and give NeuroLink the Langfuse keys, either through new NeuroLink({ observability: { langfuse } }) or the LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY environment variables. NeuroLink registers its LangfuseExporter on the shared exporter registry, which the processor reads, so mask, batching, chunking and retry from the section above all apply. Register the processor before the first NeuroLink call; spans that end before the exporter is registered are not exported.\n\n(b) LangfuseSpanProcessor. Add new LangfuseSpanProcessor() from @langfuse/otel with its defaults; no custom shouldExportSpan filter is needed. Every observation span NeuroLink emits carries a gen_ai.observation.type attribute, which the default filter exports, while infrastructure spans are not exported. This path sends OTLP and keeps native Langfuse observation types. The processor takes its keys, mask, flushAt, flushInterval, exportMode, environment and release from its own constructor options and LANGFUSE_* variables. It does not read observability.langfuse from new NeuroLink(...), so those settings must be passed to the processor, and NeuroLink's exporter masking, 500-span / 3.5 MB chunking and retry policy do not apply to it.\n\nRegister your provider before the first NeuroLink call. NeuroLink never flushes or shuts down a provider it did not create. @langfuse/otel is not a dependency of NeuroLink; install it for recipe (b).","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"External OpenTelemetry provider","lvl3":""}},
3977
+ {"objectID":"be39053eddf107cc2916c84cc2e34d629a925ef52f26864ff9dd628f798d49e1","title":"Initialisation","url":"/docs/features/observability#initialisation","content":"Telemetry starts synchronously and lazily, once per process, the first time any NeuroLink span is created. That includes direct provider calls with no NeuroLink instance, for example AIProviderFactory.createProvider(...).generate(...), which are traced the same way.\n\nAn explicit observability config passed to new NeuroLink() wins over LANGFUSE_* variables when the instance is constructed before any span is created. If telemetry has already started, the config is ignored and a debug message is logged once.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Initialisation","lvl3":""}},
3978
+ {"objectID":"2f01481e1bd920ff04b7d26da5bc86efababd09cbd1f763a1f119fb7d1443582","title":"Serverless and short-lived processes","url":"/docs/features/observability#serverless-and-short-lived-processes","content":"Spans are batched. Flush before the process freezes or exits:\n\nOr send each span as it ends:\n\nshutdownOpenTelemetry() is terminal for the process: telemetry cannot restart afterwards. While other NeuroLink instances are still alive it only flushes.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Serverless and short-lived processes","lvl3":""}},
3979
+ {"objectID":"721428a68bdcef28a5437443fe5a57565c6aa3b324a48ccc39728e5d7ff25e2d","title":"Health","url":"/docs/features/observability#health","content":"isHealthy and hasProcessor are true only while a Langfuse exporter is registered, whether NeuroLink owns the provider or runs beside a host provider. With a host provider, the exporter still needs createExporterSpanProcessor() on that provider to receive spans.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Health","lvl3":""}},
3980
+ {"objectID":"68b0ab87bc1ff79e31454e9550e76c174e5a1a4628f3c9de0e74a7dc6e07bdd2","title":"Proxy","url":"/docs/features/observability#proxy","content":"The proxy records the pool account label (not an email address), sets userId and sessionId from x-neurolink-user-id and x-neurolink-session-id, names traces proxy:<model>, and records request and response bodies, usage, cost and time to first token. See the Telemetry Guide and Claude Proxy Observability.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Proxy","lvl3":""}},
3981
+ {"objectID":"818b18185bdd4b8b7003f170da3113452c78895619ec762279322c8b2b587801","title":"Voice (LiveKit)","url":"/docs/features/observability#voice-livekit","content":"Pipeline mode traces through stream() and carries the voice tag. Realtime mode records one trace per conversation turn, with transcripts as input and output and tool calls as tool records, and only when voice memory is enabled. Full transcripts are sent to Langfuse by default; use mask for sensitive data.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Voice (LiveKit)","lvl3":""}},
3982
+ {"objectID":"6ddae5fd4f96e8c2a1c9d924054685440eb46353183984ff0b8d3167e12071b8","title":"Troubleshooting","url":"/docs/features/observability#troubleshooting","content":"| Symptom | Check |\n| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Nothing reaches Langfuse | Both keys set and langfuse not false; getLangfuseHealthStatus(); call flushOpenTelemetry() on exit |\n| Spans missing with own OTEL setup | Add createExporterSpanProcessor() to your provider and pass the Langfuse keys to NeuroLink (or set LANGFUSE_*), or use new LangfuseSpanProcessor() with its own keys; register the processor before the first NeuroLink call |\n| Wrong host | Variable is LANGFUSE_BASE_URL, not LANGFUSE_BASEURL |\n| Traces stop after shutdown | shutdownOpenTelemetry() cannot be undone in the same process; use flushOpenTelemetry() |","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Troubleshooting","lvl3":""}},
3983
+ {"objectID":"c26071897c848ba9cf00651234ebd459171008740460f6075451e866420e5881","title":"Migrating from the previous version","url":"/docs/features/observability#migrating-from-the-previous-version","content":"This release is breaking.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Migrating from the previous version","lvl3":""}},
3984
+ {"objectID":"310e635468902de6eca8789d9ce5905c4ecb08a665b802119f33a6ae78a6f429","title":"Configuration fields","url":"/docs/features/observability#configuration-fields","content":"| Removed | Replacement |\n| ------------------------------------------------------------- | ----------------------------------------------------------------------- |\n| langfuse.enabled | Set the keys to enable; langfuse: false disables |\n| langfuse.userId, langfuse.sessionId | Per-call context.userId, context.sessionId, or setLangfuseContext |\n| useExternalTracerProvider, autoDetectExternalProvider | Automatic: a registered global provider is detected |\n| skipLangfuseSpanProcessor | Register your own provider; NeuroLink then adds nothing |\n| mediaUploadEnabled, LANGFUSE_MEDIA_UPLOAD_ENABLED | Removed; the exporter does not upload media |\n| autoDetectOperationName, operationName, traceNameFormat | context.traceName |\n| customAttributes | context.metadata |\n| conversationId, requestId on the config | context.conversationId, context.requestId (stored as metadata) |\n| NEUROLINK_TELEMETRY_ENABLED | Removed; the LANGFUSE_* keys enable tracing |\n| LANGFUSE_BASEURL hint | LANGFUSE_BASE_URL |","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Configuration fields","lvl3":""}},
3985
+ {"objectID":"58496b05fc501a4521336522ee26a5eb64aa0e9d6b609b350cc0813f6d453feb","title":"Exports","url":"/docs/features/observability#exports","content":"| Removed | Replacement |\n| ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |\n| initializeOpenTelemetry | Automatic on new NeuroLink() |\n| getLangfuseSpanProcessor | createExporterSpanProcessor(registry) or new LangfuseSpanProcessor() |\n| getTracerProvider, getTracer | trace.getTracer() from @opentelemetry/api |\n| getSpanProcessors | Add createExporterSpanProcessor() to your provider |\n| createContextEnricher | setLangfuseContext or per-call context |\n| isUsingExternalTracerProvider | getLangfuseHealthStatus().usingExternalProvider |\n| isLangfuseInternalSpan, langfuseShouldExportSpan | Removed; only observation spans are exported |\n| getLangfuseContext | Removed |\n| runWithCurrentLangfuseContext | context.bind(context.active(), fn) from @opentelemetry/api |\n| buildObservabilityConfigFromEnv | Removed; env keys are read automatically |\n| createMockLangfuseClient","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"Exports","lvl3":""}},
3986
+ {"objectID":"ddf06146284ab7554c88bfef97f75c42c4186a270ac952f6cb27eb9e3640217a","title":"CLI","url":"/docs/features/observability#cli","content":"| Removed | Replacement |\n| ------------------------------------ | -------------------------------------- |\n| neurolink telemetry configure | Set LANGFUSE_* environment variables |\n| neurolink telemetry list-exporters | neurolink telemetry status |\n| neurolink observability exporters | neurolink observability status |\n\nExporterRegistry, NoOpExporter, AlwaysSampler, NeverSampler and the vendor exporter classes are unchanged. NeuroLink wires only LangfuseExporter. LangfuseExporter, ExporterSpanProcessor and createExporterSpanProcessor are new root exports.","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"CLI","lvl3":""}},
3987
+ {"objectID":"9a2c99612604332f4b2bc32fb673fe19412249aba74ad41f2ed2cfd84a8d1185","title":"See Also","url":"/docs/features/observability#see-also","content":"Telemetry Guide\nClaude Proxy Observability\nAnalytics Reference","hierarchy":{"lvl0":"Features","lvl1":"Observability Guide","lvl2":"See Also","lvl3":""}},
4000
3988
  {"objectID":"1b22ff57a6c6e2525e50e02118d6029f5ee3779ef701e9fde1b7b97d1a782760","title":"Office Documents Support","url":"/docs/features/office-documents","content":"Office Documents Support\n\nNeuroLink provides seamless Office document support as a multimodal input type - attach DOCX, PPTX, and XLSX documents directly to your AI prompts for document analysis, data extraction, and content processing.\n\nOverview\n\nOffice document support in NeuroLink works as a native multimodal input - the system automatically processes Office files and passes them to the AI provider's document understanding capabilities. The system:\nValidates Office files using magic byte detection and format verification\nChecks provider compatibility (Bedrock, Vertex AI, Anthropic)\nVerifies file size limits per provider\nPasses documents directly to the provider's native document API\nWorks with providers that support native Office document processing\n\nKey Difference from PDF: Similar to PDF files, Office documents are sent as binary documents to providers with native document support. This enables analysis of formatted text, tables, charts, and embedded content within Office files.\n\nSupported File Types\n\n| Format | Extension | MIME Type | Description |\n| --------------------- | --------- | --------------------------------------------------------------------------- | -------------------------------------------------- |\n| Word Document | .docx | application/vnd.openxmlformats-officedocument.wordprocessingml.document | Microsoft Word documents with text, images, tables |\n| PowerPoint | .pptx | application/vnd.openxmlformats-officedocument.presentationml.presentation | Presentations with slides, charts, images |\n| Excel Spreadsheet | .xlsx | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | Spreadsheets with data, formulas, charts |\n\nLegacy Formats:\n\n| Format | Extension | MIME Type | Support |\n| -------------- | --------- | -------------------------- | ------------------ |\n| Word (Legacy) | .doc | application/msword | Provider-dependent |\n| Excel (Legacy) | .xls | application/vnd.ms-excel | Provider-dependent |\n\nQuick Start\n\nSDK Usage\n\nCLI Usage\n\nAPI Reference\n\nGenerateOptions\n\nStreamOptions\n\nOfficeProcessorOptions\n\nOnly sheetName and formatStyle are read by the XLSX pipeline today; the\nother fields are declared but not yet consumed.\n\nDOCX structure and metrics\n\nA .docx is converted to Markdown before it reaches the model, so headings,\nordered and unordered lists, and tables survive as structure rather than being\nflattened into prose. Each document is prefixed with a metrics line:\n\nThis needs no configuration and applies to every provider, because the\nconversion happens while the prompt is built rather than in a provider adapter.\n\nSelecting and formatting spreadsheet data\n\nNaming a sheet that does not exist does not silently fall back to every sheet —\nthe prompt reports the miss and lists the available sheet names.\n\nFile Input Formats\n\nProvider Support\n\nSupported Providers\n\n| Provider | Max Size | DOCX | PPTX | XLSX | DOC | XLS | Notes |\n| -------------------- | -------- | ---- | ---- | ---- | --- | --- | ------------------------------------ |\n| AWS Bedrock | 5 MB | ✅ | ✅ | ✅ | ✅ | ✅ | Full native support via Converse API |\n| Google Vertex AI | 5 MB | ✅ | ⚠️ | ✅ | ⚠️ | ⚠️ | Best for DOCX and XLSX |\n| Anthropic Claude | 5 MB | ✅ | ⚠️ | ✅ | ⚠️ | ⚠️ | Via document API |\n\nUnsupported Providers\n\nThe following providers do not currently support native Office document processing:\nOpenAI (GPT-4o)\nGoogle AI Studio\nAzure OpenAI\nOllama (local models)\nLiteLLM\nMistral AI\nHugging Face\n\nError Message for Unsupported Providers:\n\nProvider-Specific Features\n\nAWS Bedrock (Recommended)\n\nBedrock offers the most comprehensive Office document support via the Converse API:\n\nSupported Document Formats in Bedrock Converse API:\nOffice formats: doc, docx, xls, xlsx\nOther formats: pdf, csv, html, txt, md\n\nGoogle Vertex AI\n\nAnthropic Claude\n\nFeatures\nAuto-Detection\n\nUse the files array for automatic file type detection:\nMultiple Document Types\n\nProcess multiple Office documents in a single request:\nMixed Multimodal Inputs\n\nCombine Office documents with other file types:\n\nType Definitions\n\nOfficeFileType\n\nOfficeProcessingResult\n\nOfficeProviderConfig\n\nError Handling\n\nError Types\n\nError Handling Patterns\n\nMetadata Fields\n\nWhen processing Office documents, the following metadata is available:\n\n| Field | Type | Description |\n| ------------------- | ---------------- | -------------------------------- |\n| confidence | number | Detection confidence (0-100) |\n| size | number | File size in bytes |\n| filename | string | Original filename |\n| format | OfficeFileT","hierarchy":{"lvl0":"Features","lvl1":"Office Documents Support","lvl2":"","lvl3":""}},
4001
3989
  {"objectID":"20c3155d2c1f39db07b8ffb72304d589cb601d27d43fb6f6f81ec8e83b5af4f2","title":"Office Documents Support","url":"/docs/features/office-documents#office-documents-support","content":"NeuroLink provides seamless Office document support as a multimodal input type - attach DOCX, PPTX, and XLSX documents directly to your AI prompts for document analysis, data extraction, and content processing.","hierarchy":{"lvl0":"Features","lvl1":"Office Documents Support","lvl2":"Office Documents Support","lvl3":""}},
4002
3990
  {"objectID":"89922c3be7ba989417dd4f9aa76cf3c0497898b83d430c80f5809846a01ebcab","title":"Overview","url":"/docs/features/office-documents#overview","content":"Office document support in NeuroLink works as a native multimodal input - the system automatically processes Office files and passes them to the AI provider's document understanding capabilities. The system:\nValidates Office files using magic byte detection and format verification\nChecks provider compatibility (Bedrock, Vertex AI, Anthropic)\nVerifies file size limits per provider\nPasses documents directly to the provider's native document API\nWorks with providers that support native Office document processing\n\nKey Difference from PDF: Similar to PDF files, Office documents are sent as binary documents to providers with native document support. This enables analysis of formatted text, tables, charts, and embedded content within Office files.","hierarchy":{"lvl0":"Features","lvl1":"Office Documents Support","lvl2":"Overview","lvl3":""}},
@@ -4232,7 +4220,7 @@
4232
4220
  {"objectID":"439bf40cab58d82bc1488de91f2152f91d3ff65586aaa4616577f8bdae040075","title":"1. The shape of the problem","url":"/docs/features/proxy-cli-onboarding#1-the-shape-of-the-problem","content":"The proxy is a Hono app bound to 127.0.0.1:55669 by default (proxy.ts:3864,\n:4532, :5590; port default 55669 at :4536). It terminates a CLI's own OAuth\ntoken, swaps in one from a pooled account, forwards upstream, and relays SSE back.\n\nIt exposes three wire surfaces:\n\n| Door | Factory | Upstream |\n| ----------------------------------- | ------------------------------------------------------- | --------------------------------------- |\n| POST /v1/messages | createClaudeProxyRoutes (claudeProxyRoutes.ts:8316) | api.anthropic.com |\n| POST /v1/chat/completions | createOpenAIProxyRoutes (openaiProxyRoutes.ts:351) | translation engine / Anthropic loopback |\n| POST /backend-api/codex/responses | createCodexProxyRoutes (codexProxyRoutes.ts:568) | chatgpt.com/backend-api |\n\nDispatch is by URL path. A CLI is \"onboarded\" by writing _that CLI's own config\nfile_ so it points at the right door. Three such writers exist, hand-authored, sharing\nno abstraction:\n\n| CLI | Writer | Restore | Target |\n| ----------- | --------------------------------------------- | --------------------------------------- | ---------------------------------- |\n| Claude Code | setClaudeProxySettings proxy.ts:625-652 | clearClaudeProxySettings :654 | ~/.claude/settings.json (:248) |\n| OpenCode | setOpenCodeProxySettings proxy.ts:734-784 | clearOpenCodeProxySettings :786-843 | opencode.json (:722) |\n| Codex | setCodexProxySettings proxy.ts:922-994 | clearCodexProxySettings :996 | ~/.codex/config.toml (:857) |\n\n/v1/chat/completions is the important door and nothing is pointed at it.","hierarchy":{"lvl0":"Features","lvl1":"Onboarding a New AI Coding CLI onto the NeuroLink Proxy","lvl2":"1. The shape of the problem","lvl3":""}},
4233
4221
  {"objectID":"c1678ee68815daa3446f700aafd2ef5a7536ca51886ffbeb8e8989d38fbf0b1b","title":"Coverage, verified on this machine","url":"/docs/features/proxy-cli-onboarding#coverage-verified-on-this-machine","content":"| CLI | Installed | Verdict | Mechanism |\n| ------------ | ----------------------------- | ------------------------- | -------------------------------------------------------------- |\n| Claude Code | yes | live | ANTHROPIC_BASE_URL |\n| Codex | yes | live | config.toml base_url + wire_api=\"responses\" |\n| OpenCode | 1.3.13 | live | provider.neurolink in opencode.json (fixed: #1366/#1367) |\n| Qwen Code | @qwen-code/qwen-code@0.17.0 | live | security.auth.baseUrl → /v1/chat/completions |\n| Copilot CLI | @github/copilot@1.0.56 | live | COPILOT_PROVIDER_* via a sourceable env script |\n| Hermes Agent | no | easy (unverified on disk) | ANTHROPIC_BASE_URL / OPENAI_BASE_URL |\n| Gemini CLI | @google/gemini-cli@0.53.0 | moderate | GOOGLE_GEMINI_BASE_URL, API-key mode only |\n| Amp | 0.0.1780291930-gf6d536 | hard | AMP_URL honoured, but fronts a proprietary backend — see §7c |\n| Cursor | cursor-agent 2026.05.28 | refuted | env vars are dead code — proven by live test |\n| Antigravity | 1.107.0 | hard | proprietary Cascade protobuf |\n| Grok CLI | no | unconfirmed | not installed |\n| Kiro CLI | no | hard | fixed AWS hosts, OAuth device flow |\n\nNear-term: 2 live → 6 — five of those are now live (Claude Code, Codex,","hierarchy":{"lvl0":"Features","lvl1":"Onboarding a New AI Coding CLI onto the NeuroLink Proxy","lvl2":"Coverage, verified on this machine","lvl3":""}},
4234
4222
  {"objectID":"d002685bad412b4ea546cccc1ebd7441570e08708eb3fb3d8a6ead1898f5edb4","title":"2. Corrections to the v11.2.2 audit","url":"/docs/features/proxy-cli-onboarding#2-corrections-to-the-v1122-audit","content":"The earlier audit's structural claims hold. Five of its specific claims do not.","hierarchy":{"lvl0":"Features","lvl1":"Onboarding a New AI Coding CLI onto the NeuroLink Proxy","lvl2":"2. Corrections to the v11.2.2 audit","lvl3":""}},
4235
- {"objectID":"078d30f3c31c850d03257e95c48d42c113019b6fd26ccf46bb076eb1755cd92f","title":"2.1 The cost defect is attributed to the wrong route — and the failure mode is different","url":"/docs/features/proxy-cli-onboarding#21-the-cost-defect-is-attributed-to-the-wrong-route-and-the-failure-mode-is-different","content":"Claimed: proxyTracer.ts:497 and :826 hard-code calculateCost(\"anthropic\", …),\nso Codex traffic to chatgpt.com is costed against Anthropic's price table.\n\nActually:\nThere are four hard-coded \"anthropic\" sites, not two: proxyTracer.ts:497,\n :826, :874 (all calculateCost) and :883\n (TelemetryService.recordAIRequest(\"anthropic\", …)).\ncodexProxyRoutes.ts never imports ProxyTracer and never calls\n calculateCost. Its logRequest() object literal (:322-339) has no token keys\n at all, and it never parses usage out of the SSE stream. Codex traffic is not\n mis-priced — it is entirely unaccounted. Fixing it starts with parsing usage,\n not with the pricing call.\nThe hard-coded provider actually mis-prices /v1/chat/completions, which routes\n through ModelRouter to any provider.\nThe failure mode is usually $0, not a wrong number. findRates returns\n undefined when nothing matches, and calculateCost then returns 0\n (pricing.ts:755-758). The anthropic table (pricing.ts:26-161) has no\n _default sentinel — the first one is at :406. So findRates(\"anthropic\",\n\"gpt-4o\") → undefined → $0. Real mis-pricing only happens when a\n Claude-named model is routed elsewhere (e.g. a claude-* alias mapped to Vertex\n Gemini), which prices Gemini traffic at Sonnet rates.\nCompounding it: ProxyTracer.model is private readonly (proxyTracer.ts:248),\n fixed at construction to the model the client asked for.\n setModelSubstitution() only writes span attributes. So even with a correct\n provider string, cost is computed against the requested model, not the served one.\n\nGood news: pricing.ts already ships 18 provider tables including openai with a\n\"gpt-5.1-codex\" entry (:162+). For the /v1/chat/completions path this is a\nparameter change, not new pricing data.","hierarchy":{"lvl0":"Features","lvl1":"Onboarding a New AI Coding CLI onto the NeuroLink Proxy","lvl2":"2.1 The cost defect is attributed to the wrong route — and the failure mode is different","lvl3":""}},
4223
+ {"objectID":"078d30f3c31c850d03257e95c48d42c113019b6fd26ccf46bb076eb1755cd92f","title":"2.1 The cost defect is attributed to the wrong route — and the failure mode is different","url":"/docs/features/proxy-cli-onboarding#21-the-cost-defect-is-attributed-to-the-wrong-route-and-the-failure-mode-is-different","content":"Claimed: proxyTracer.ts:497 and :826 hard-code calculateCost(\"anthropic\", …),\nso Codex traffic to chatgpt.com is costed against Anthropic's price table.\n\nActually:\nThere are four hard-coded \"anthropic\" sites, not two: proxyTracer.ts:497,\n :826, :874 (all calculateCost) and :883\n (the recordAIRequest metric call).\ncodexProxyRoutes.ts never imports ProxyTracer and never calls\n calculateCost. Its logRequest() object literal (:322-339) has no token keys\n at all, and it never parses usage out of the SSE stream. Codex traffic is not\n mis-priced — it is entirely unaccounted. Fixing it starts with parsing usage,\n not with the pricing call.\nThe hard-coded provider actually mis-prices /v1/chat/completions, which routes\n through ModelRouter to any provider.\nThe failure mode is usually $0, not a wrong number. findRates returns\n undefined when nothing matches, and calculateCost then returns 0\n (pricing.ts:755-758). The anthropic table (pricing.ts:26-161) has no\n _default sentinel — the first one is at :406. So findRates(\"anthropic\",\n\"gpt-4o\") → undefined → $0. Real mis-pricing only happens when a\n Claude-named model is routed elsewhere (e.g. a claude-* alias mapped to Vertex\n Gemini), which prices Gemini traffic at Sonnet rates.\nCompounding it: ProxyTracer.model is private readonly (proxyTracer.ts:248),\n fixed at construction to the model the client asked for.\n setModelSubstitution() only writes span attributes. So even with a correct\n provider string, cost is computed against the requested model, not the served one.\n\nGood news: pricing.ts already ships 18 provider tables including openai with a\n\"gpt-5.1-codex\" entry (:162+). For the /v1/chat/completions path this is a\nparameter change, not new pricing data.","hierarchy":{"lvl0":"Features","lvl1":"Onboarding a New AI Coding CLI onto the NeuroLink Proxy","lvl2":"2.1 The cost defect is attributed to the wrong route — and the failure mode is different","lvl3":""}},
4236
4224
  {"objectID":"0e958f52839eaf1faa4147d73bb91f8ed4ce2058629b7169b3ac3d59cae3dc30","title":"2.2 \"Nothing identifies the calling CLI at request time\" is false — and this is an onboarding hazard","url":"/docs/features/proxy-cli-onboarding#22-nothing-identifies-the-calling-cli-at-request-time-is-false-and-this-is-an-onboarding-hazard","content":"Claimed: detectClientApp() (proxyTracer.ts:226-235) is the only User-Agent\nsniff and it only labels trace spans.\n\nActually: there is a second sniff that drives real request behaviour.\nisLikelyClaudeClient() (claudeProxyRoutes.ts:2341-2350) tests\nheaders[\"user-agent\"]?.startsWith(\"claude-cli/\") (among other signals), and its\nresult gates:\nwhich OAuth beta header set is sent — CLAUDE_CODE_OAUTH_BETAS vs\n NON_CLAUDE_OAUTH_BETAS (:7221-7236);\nwhether polyfillOAuthBody() preserves the client's own system-prompt / agent\n identity blocks verbatim or strips and relocates them;\nmaybeRefreshClaudeSnapshot() (:2398).\n\nThis matters directly for CLI #4 and #5. Any non-Claude CLI pointed at\n/v1/messages via ANTHROPIC_BASE_URL — Hermes is exactly this case — takes the\nNON_CLAUDE_OAUTH_BETAS branch and a different system-prompt path. That is probably\ncorrect behaviour, but it is behaviour, and it must be tested rather than assumed.","hierarchy":{"lvl0":"Features","lvl1":"Onboarding a New AI Coding CLI onto the NeuroLink Proxy","lvl2":"2.2 \"Nothing identifies the calling CLI at request time\" is false — and this is an onboarding hazard","lvl3":""}},
4237
4225
  {"objectID":"8997754a7d1d3258d747dd7590b34765a6d34d8c36e642f970247618d869e78e","title":"2.3 \"314,116 requests and no ledger\" is overstated","url":"/docs/features/proxy-cli-onboarding#23-314116-requests-and-no-ledger-is-overstated","content":"usageStats.ts (1,478 lines, zero occurrences of inputTokens / outputTokens /\ntotalTokens / cost) is confirmed. But neurolink proxy analyze is a real, wired\ncommand (src/cli/parser.ts:260) and proxyAnalysis.ts:437-527 reads the same\nproxy-YYYY-MM-DD.jsonl files requestLogger.ts writes and sums inputTokens,\ncacheReadTokens and cacheCreationTokens per window.\n\nThe gap is narrower and more specific than \"no ledger\": outputTokens and cost\nare absent from proxyAnalysis.ts entirely, and nothing aggregates the Codex engine\nat all (§2.1).","hierarchy":{"lvl0":"Features","lvl1":"Onboarding a New AI Coding CLI onto the NeuroLink Proxy","lvl2":"2.3 \"314,116 requests and no ledger\" is overstated","lvl3":""}},
4238
4226
  {"objectID":"081076044aa5320358b560458b66d5725f4a5776d94e808e16b6961541789dcc","title":"2.4 OpenCode is two bugs, not a one-line fix","url":"/docs/features/proxy-cli-onboarding#24-opencode-is-two-bugs-not-a-one-line-fix","content":"The path bug is confirmed and is genuinely one line — but a path-only fix leaves a\nsecond, independent bug in place.\ngetOpenCodeConfigDir() (proxy.ts:711-720) returns\n ~/Library/Application Support/opencode on darwin. The installed OpenCode 1.3.13\n binary embeds the unmodified xdg-basedir npm package\n (XDG_CONFIG_HOME || join(homedir, \".config\")) with no platform branch at all.\n Empirically: ~/.config/opencode/opencode.json exists (2,640 bytes, holds a working\n custom provider that opencode models confirms is loaded);\n ~/Library/Application Support/opencode does not exist. Deleting the darwin\n branch is the whole fix.\nThe second bug survives that. setOpenCodeProxySettings returns Promise<void>\n (:734) and the call sites print ✓ Auto-configured OpenCode settings\n unconditionally (:3491-3493, :5403-5405). setCodexProxySettings returns\n Promise<boolean> and its ✓ is gated on it (:3502, :5413). So even after the\n path fix, a user without OpenCode installed still gets a success message for work\n that did not happen.\n\nOrigin of the mistake: the OpenCode binary does contain the literal\n/Library/Application Support/opencode — as systemManagedConfigDir(), an MDM /\nenterprise policy tier at the filesystem root (no $HOME), paired with\n/etc/opencode and %ProgramData%\\opencode. Someone found that string and read it as\nthe per-user path.\n\nIt is also baked into our own docs. docs/features/opencode-proxy-support.md:67\nasserts the macOS path is ~/Library/Application Support/opencode/opencode.json,\nwhile :313-323 of the same file shows resolution code with no darwin branch that\nwould compute ~/.config/opencode. The doc contradicts itself, and it is titled\n\"Implemented & Verified\".\n\nHow it escaped verification: §11's E2E playbook runs the dev proxy with --dev,\nwhich by its own option description performs \"no client auto-configuration\"\n(proxy.ts:3910-3917), and hand-copies a fixture to\n/tmp/opencode-proxy-test/opencode.json. The writer is never executed.","hierarchy":{"lvl0":"Features","lvl1":"Onboarding a New AI Coding CLI onto the NeuroLink Proxy","lvl2":"2.4 OpenCode is two bugs, not a one-line fix","lvl3":""}},
@@ -8574,7 +8562,7 @@
8574
8562
  {"objectID":"7826f375db586c8004183275c0715b410e96f673701874419ba565b6ff3dd214","title":"When to Use","url":"/docs/guides/server-adapters/middleware#when-to-use-9","content":"API abuse prevention\nFair usage enforcement\nCost control for expensive operations\nProtection against DDoS attacks","hierarchy":{"lvl0":"Guides","lvl1":"Middleware Reference","lvl2":"When to Use","lvl3":""}},
8575
8563
  {"objectID":"ce6af8a97b716420a9742ad3d965d5cb0aa5912e3d52d961814c83e9e1abaa19","title":"Authentication Middleware","url":"/docs/guides/server-adapters/middleware#authentication-middleware","content":"Provides flexible authentication support with multiple strategies.","hierarchy":{"lvl0":"Guides","lvl1":"Middleware Reference","lvl2":"Authentication Middleware","lvl3":""}},
8576
8564
  {"objectID":"dc019f0ad08d89054d4f68945d6855bbc6d74da0b3f8082e35f56fa5f731ec51","title":"Headers Read","url":"/docs/guides/server-adapters/middleware#headers-read","content":"| Header | Auth Type | Description |\n| --------------- | ------------- | ------------------------------------ |\n| Authorization | bearer, basic | Bearer <token> or Basic <base64> |\n| X-API-Key | api-key | Raw API key value |","hierarchy":{"lvl0":"Guides","lvl1":"Middleware Reference","lvl2":"Headers Read","lvl3":""}},
8577
- {"objectID":"43776c9da774387f221eb7918931d5a4a59b42c949ef248c30c7afb5512ee7ea","title":"Dev Playground Support","url":"/docs/guides/server-adapters/middleware#dev-playground-support","content":"In non-production environments, requests with X-NeuroLink-Dev-Playground: true header bypass authentication and receive a default developer user context.","hierarchy":{"lvl0":"Guides","lvl1":"Middleware Reference","lvl2":"Dev Playground Support","lvl3":""}},
8565
+ {"objectID":"43776c9da774387f221eb7918931d5a4a59b42c949ef248c30c7afb5512ee7ea","title":"Dev Playground Support","url":"/docs/guides/server-adapters/middleware#dev-playground-support","content":"Requests with an X-NeuroLink-Dev-Playground: true (or X-NeuroLink-Playground: true) header bypass authentication and receive a default developer user context (id: \"playground\", roles: [\"developer\"]), but only when NODE_ENV is exactly development. The variable is read on every request.\n\nWith NODE_ENV unset, production, test, staging or any other value, the header is ignored and the request must carry a valid credential. The bypass is therefore off by default in a deployment that never sets NODE_ENV. Pass skipDevPlayground: false to refuse the header even in development.","hierarchy":{"lvl0":"Guides","lvl1":"Middleware Reference","lvl2":"Dev Playground Support","lvl3":""}},
8578
8566
  {"objectID":"a2d39b213dc8603fb3d7889b019eebc14f3705eb13b1185d7f98bf26d988f4aa","title":"When to Use","url":"/docs/guides/server-adapters/middleware#when-to-use-10","content":"Protecting API endpoints\nUser identification and authorization\nRate limiting by user\nAudit logging","hierarchy":{"lvl0":"Guides","lvl1":"Middleware Reference","lvl2":"When to Use","lvl3":""}},
8579
8567
  {"objectID":"fb39a14f946d17f7771143d4e3c349bc51999e8aa360456371d0b8dec29a6449","title":"Request Validation Middleware","url":"/docs/guides/server-adapters/middleware#request-validation-middleware","content":"Provides schema-based request validation for body, query, params, and headers.","hierarchy":{"lvl0":"Guides","lvl1":"Middleware Reference","lvl2":"Request Validation Middleware","lvl3":""}},
8580
8568
  {"objectID":"82758f32126cb9af5f9e25763494cfdbba464d89d977e292be0ad93ce5407717","title":"Common Schemas","url":"/docs/guides/server-adapters/middleware#common-schemas","content":"Pre-built schemas for common validation patterns:\n\n| Schema | Fields |\n| ------------ | ----------------------------- |\n| uuid | UUID string format |\n| email | Email string format |\n| pagination | page, limit, offset |\n| sorting | sortBy, sortOrder |\n| idParam | Required id parameter |\n| dateRange | startDate, endDate |\n| search | q (query), fields (array) |","hierarchy":{"lvl0":"Guides","lvl1":"Middleware Reference","lvl2":"Common Schemas","lvl3":""}},
@@ -9098,27 +9086,17 @@
9098
9086
  {"objectID":"59eb055362db31f6109fac03cd915ae19f1bc96bce71d1c8f893dc00fa9cb106","title":"Test specific provider","url":"/docs/observability/provider-status#test-specific-provider","content":"GOOGLEAIAPI_KEY=your-key npx @juspay/neurolink status --json | jq '.providers.\"google-ai\"'","hierarchy":{"lvl0":"Observability","lvl1":"Provider Status Monitoring and Health Management","lvl2":"Test specific provider","lvl3":""}},
9099
9087
  {"objectID":"ed73ab4617eea518c699e2c89e7b9e5ef38ee5ed43dcadcdf98f14dfbe4da6e5","title":"Check demo server status (if running)","url":"/docs/observability/provider-status#check-demo-server-status-if-running","content":"curl http://localhost:9876/api/status\n`","hierarchy":{"lvl0":"Observability","lvl1":"Provider Status Monitoring and Health Management","lvl2":"Check demo server status (if running)","lvl3":""}},
9100
9088
  {"objectID":"e938db7055d0bdcf6a8aae0a76a7fc8aa1dc9496409d6c457136e5765a1cc5cc","title":"Conclusion","url":"/docs/observability/provider-status#conclusion","content":"NeuroLink's Provider Status Monitoring system provides enterprise-grade health management for AI provider infrastructure. With real-time monitoring, intelligent recommendations, and comprehensive analytics, it ensures optimal provider selection and proactive issue resolution.\n\nKey benefits include:\nProactive Issue Detection: Identify problems before they impact production\nIntelligent Provider Selection: Automatic optimization for performance and cost\nOperational Excellence: Complete visibility into AI infrastructure health\nDeveloper Productivity: Actionable recommendations reduce debugging time\n\nThis system transforms AI provider management from reactive troubleshooting to proactive optimization, ensuring reliable and efficient AI operations at enterprise scale.","hierarchy":{"lvl0":"Observability","lvl1":"Provider Status Monitoring and Health Management","lvl2":"Conclusion","lvl3":""}},
9101
- {"objectID":"3abc8984be035e0f7eaeeee65f8d8f2fab3f41ecc96355a2456d62170d25c333","title":"📊 Enterprise Telemetry Guide","url":"/docs/observability/telemetry","content":"📊 Enterprise Telemetry Guide\n\nAdvanced OpenTelemetry Integration for NeuroLink\n\n📋 Overview\n\nNeuroLink includes optional OpenTelemetry integration for enterprise monitoring and observability. The telemetry system provides comprehensive insights into AI operations, performance metrics, and system health with zero overhead when disabled.\n\n🚀 Key Features\n✅ Zero Overhead by Default - Telemetry disabled unless explicitly configured\n🤖 AI Operation Tracking - Monitor text generation, token usage, costs, and response times\n🔧 MCP Tool Monitoring - Track tool calls, execution time, and success rates\n📈 Performance Metrics - Response times, error rates, throughput monitoring\n🔍 Distributed Tracing - Full request tracing across AI providers and services\n📊 Custom Dashboards - Grafana, Jaeger, and Prometheus integration\n🎯 Production Ready - Enterprise-grade monitoring for production deployments\n\n🎯 Langfuse Integration\n\nNeuroLink provides native integration with Langfuse for LLM-specific observability.\n\nQuick Setup\n\nContext Enrichment\n\nAdd user, session, and custom metadata to your traces:\n\nCustom Spans\n\nCreate your own spans for detailed tracing:\n\nExternal TracerProvider Mode\n\nIf your application already has OpenTelemetry instrumentation, use external provider mode:\n\nVercel AI SDK Integration\n\nIf your application also uses the Vercel AI SDK, NeuroLink's ContextEnricher reads the GenAI semantic-convention attributes that experimental_telemetry emits. NeuroLink itself has no dependency on the ai package — the imports below are your application's, and the SDK is not required to use NeuroLink:\n\n🔧 Basic Setup\n\nEnvironment Configuration\n\nProgrammatic Initialization\n\nEnvironment Variables\n\n| Variable | Description | Default |\n| ----------------------------- | ------------------------ | -------------- |\n| NEUROLINK_TELEMETRY_ENABLED | Enable/disable telemetry | false |\n| OTEL_EXPORTER_OTLP_ENDPOINT | OTLP endpoint URL | - |\n| OTEL_SERVICE_NAME | Service name | neurolink-ai |\n| OTEL_SERVICE_VERSION | Service version | 3.0.1 |\n\n🔭 Proxy Telemetry (OTLP Triple-Signal Export)\n\nWhen running the NeuroLink proxy (neurolink proxy start), OpenTelemetry is automatically initialized. If OTEL_EXPORTER_OTLP_ENDPOINT is set, the proxy exports three signal types via OTLP HTTP:\n\n| Signal | Endpoint | What it captures |\n| ------- | ----------------------------------------- | ------------------------------------------------------------------ |\n| Traces | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/traces | Per-request spans: receive → account selection → upstream → stream |\n| Metrics | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/metrics | Request counters, latency histograms, token usage gauges |\n| Logs | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/logs | Structured request log records with traceId/spanId correlation |\n\nConfiguration: Set OTEL_EXPORTER_OTLP_ENDPOINT (e.g., http://localhost:4318) before starting the proxy. The proxy defaults to service.name=neurolink-proxy.\n\nTrace correlation: Every JSONL request log entry includes traceId and spanId fields, enabling cross-signal correlation in backends like Jaeger, Grafana Tempo, or OpenObserve.\n\nCaller trace linkage: When a calling SDK already has an active trace, NeuroLink forwards W3C traceparent/tracestate headers and x-neurolink-session-id / x-neurolink-user-id / x-neurolink-conversation-id headers into the proxy so proxy spans can attach to the caller trace and preserve session-level attribution.\n\nTelemetryService reuse: If a global TracerProvider is already registered (e.g., by the host application), TelemetryService will reuse it instead of creating a duplicate — avoiding \"already registered\" errors.\n\nOpenObserve dashboard: The maintained proxy dashboard definition lives in docs/assets/dashboards/neurolink-proxy-observability-dashboard.json. For how to read that dashboard and which streams it should use, see Claude Proxy Observability.\n\nLocal OpenObserve Setup For The Proxy\n\nFor a new local setup, use the repo-owned files in scripts/observability/ so the proxy dashboard does not depend on the Curator repo.\nOptional: copy scripts/observability/proxy-observability.env.example to scripts/observability/proxy-observability.env if the default ports or credentials clash with your machine.\nStart OpenObserve, start the OTEL collector, and import the dashboard:\nStart the proxy with the collector endpoint printed by the setup script. With the defaults, that is:\nOpen the UI at http://localhost:5080 and sign in with the configured OpenObserve credentials.\n\nUseful follow-up commands:\n\nWhen you are working from a local checkout instead of an installed CLI, pnpm run proxy:observability:* provides the same actions as repo shortcuts.\n\nWhat is machine-specific:\nOpenObserve URL, credentials, ports, container names, and v","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"","lvl3":""}},
9089
+ {"objectID":"3abc8984be035e0f7eaeeee65f8d8f2fab3f41ecc96355a2456d62170d25c333","title":"📊 Enterprise Telemetry Guide","url":"/docs/observability/telemetry","content":"📊 Enterprise Telemetry Guide\n\nAdvanced OpenTelemetry Integration for NeuroLink\n\n📋 Overview\n\nNeuroLink includes optional OpenTelemetry integration for enterprise monitoring and observability. The telemetry system provides comprehensive insights into AI operations, performance metrics, and system health with zero overhead when disabled.\n\n🚀 Key Features\n✅ Zero Overhead by Default - Telemetry disabled unless explicitly configured\n🤖 AI Operation Tracking - Monitor text generation, token usage, costs, and response times\n🔧 MCP Tool Monitoring - Track tool calls, execution time, and success rates\n📈 Performance Metrics - Response times, error rates, throughput monitoring\n🔍 Distributed Tracing - Full request tracing across AI providers and services\n📊 Custom Dashboards - Grafana, Jaeger, and Prometheus integration\n🎯 Production Ready - Enterprise-grade monitoring for production deployments\n\nLangfuse Integration\n\nSet LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY and NeuroLink exports every AI operation to Langfuse. Pass observability: { langfuse: false } to disable. Full input and output are captured by default; use mask for sensitive data.\n\nIf your application already registers an OpenTelemetry TracerProvider, NeuroLink creates no provider but registers its Langfuse exporter when keys are configured; add createExporterSpanProcessor() to your provider (recommended), or add new LangfuseSpanProcessor() from @langfuse/otel with its own keys (no custom filter is needed because every NeuroLink observation span carries gen_ai.observation.type and infrastructure spans are not exported; NeuroLink's mask, chunking and retry do not apply to it). In serverless, call flushOpenTelemetry() before exit.\n\nThe full guide, including the migration table for removed fields and exports, is Observability.\n\nBasic Setup\n\nEnvironment Variables\n\n| Variable | Description | Default |\n| ----------------------------- | ---------------------------------------------------- | -------------- |\n| LANGFUSE_PUBLIC_KEY | Langfuse public key; with the secret key, enables it | - |\n| LANGFUSE_SECRET_KEY | Langfuse secret key | - |\n| LANGFUSE_BASE_URL | Langfuse host | Langfuse Cloud |\n| OTEL_EXPORTER_OTLP_ENDPOINT | OTLP collector endpoint for traces and metrics | - |\n| OTEL_SERVICE_NAME | Service name | neurolink-ai |\n\n🔭 Proxy Telemetry (OTLP Triple-Signal Export)\n\nWhen running the NeuroLink proxy (neurolink proxy start), OpenTelemetry is automatically initialized. If OTEL_EXPORTER_OTLP_ENDPOINT is set, the proxy exports three signal types via OTLP HTTP:\n\n| Signal | Endpoint | What it captures |\n| ------- | ----------------------------------------- | ------------------------------------------------------------------ |\n| Traces | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/traces | Per-request spans: receive → account selection → upstream → stream |\n| Metrics | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/metrics | Request counters, latency histograms, token usage gauges |\n| Logs | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/logs | Structured request log records with traceId/spanId correlation |\n\nConfiguration: Set OTEL_EXPORTER_OTLP_ENDPOINT (e.g., http://localhost:4318) before starting the proxy. The proxy defaults to service.name=neurolink-proxy.\n\nTrace correlation: Every JSONL request log entry includes traceId and spanId fields, enabling cross-signal correlation in backends like Jaeger, Grafana Tempo, or OpenObserve.\n\nCaller trace linkage: When a calling SDK already has an active trace, NeuroLink forwards W3C traceparent/tracestate headers and x-neurolink-session-id / x-neurolink-user-id / x-neurolink-conversation-id headers into the proxy so proxy spans can attach to the caller trace and preserve session-level attribution.\n\nProvider reuse: If a global TracerProvider is already registered (e.g., by the host application), NeuroLink registers nothing and uses it, avoiding \"already registered\" errors.\n\nOpenObserve dashboard: The maintained proxy dashboard definition lives in docs/assets/dashboards/neurolink-proxy-observability-dashboard.json. For how to read that dashboard and which streams it should use, see Claude Proxy Observability.\n\nLocal OpenObserve Setup For The Proxy\n\nFor a new local setup, use the repo-owned files in scripts/observability/ so the proxy dashboard does not depend on the Curator repo.\nOptional: copy scripts/observability/proxy-observability.env.example to scripts/observability/proxy-observability.env if the default ports or credentials clash with your machine.\nStart OpenObserve, start the OTEL collector, and import the dashboard:\nStart the proxy with the collector endpoint printed by the setup script. W","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"","lvl3":""}},
9102
9090
  {"objectID":"5bca8b67352628f2ead424686c839896c0c9191fbe9bc9ce9f2b4f1a34fda7b4","title":"📊 Enterprise Telemetry Guide","url":"/docs/observability/telemetry#-enterprise-telemetry-guide","content":"Advanced OpenTelemetry Integration for NeuroLink","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"📊 Enterprise Telemetry Guide","lvl3":""}},
9103
9091
  {"objectID":"01dd892f6d8681fb916960f5512d67fc1772f13906d80f188160040a7d13352b","title":"📋 Overview","url":"/docs/observability/telemetry#-overview","content":"NeuroLink includes optional OpenTelemetry integration for enterprise monitoring and observability. The telemetry system provides comprehensive insights into AI operations, performance metrics, and system health with zero overhead when disabled.","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"📋 Overview","lvl3":""}},
9104
9092
  {"objectID":"1560608dd386dd63e33cf859910b21ae292c6d2b3a5e5c20c6b758b509e91665","title":"🚀 Key Features","url":"/docs/observability/telemetry#-key-features","content":"✅ Zero Overhead by Default - Telemetry disabled unless explicitly configured\n🤖 AI Operation Tracking - Monitor text generation, token usage, costs, and response times\n🔧 MCP Tool Monitoring - Track tool calls, execution time, and success rates\n📈 Performance Metrics - Response times, error rates, throughput monitoring\n🔍 Distributed Tracing - Full request tracing across AI providers and services\n📊 Custom Dashboards - Grafana, Jaeger, and Prometheus integration\n🎯 Production Ready - Enterprise-grade monitoring for production deployments","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"🚀 Key Features","lvl3":""}},
9105
- {"objectID":"5d977b9b728010d34b7599214762903dff90b4fd55b436529717e66909c8cc0e","title":"🎯 Langfuse Integration","url":"/docs/observability/telemetry#-langfuse-integration","content":"NeuroLink provides native integration with Langfuse for LLM-specific observability.","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"🎯 Langfuse Integration","lvl3":""}},
9106
- {"objectID":"13b0495bd3990a038de191fae9b9b3ddd4ff63dbd872c582df479f641d35ffe0","title":"Context Enrichment","url":"/docs/observability/telemetry#context-enrichment","content":"Add user, session, and custom metadata to your traces:","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Context Enrichment","lvl3":""}},
9107
- {"objectID":"70549a9b12afcca5ca7606787d0293edd06ad1a79d472a2a92a1007b8904aa06","title":"Custom Spans","url":"/docs/observability/telemetry#custom-spans","content":"Create your own spans for detailed tracing:","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Custom Spans","lvl3":""}},
9108
- {"objectID":"47c2396523cf326c1efca27b28f3b87b1a33203a302431fc59cdbd3a2b77dc5a","title":"External TracerProvider Mode","url":"/docs/observability/telemetry#external-tracerprovider-mode","content":"If your application already has OpenTelemetry instrumentation, use external provider mode:","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"External TracerProvider Mode","lvl3":""}},
9109
- {"objectID":"8f5b35a0bd6e0a2e74bfccf23f88d087166c8b302379ca9a06c05cd4db3c52a4","title":"Vercel AI SDK Integration","url":"/docs/observability/telemetry#vercel-ai-sdk-integration","content":"If your application also uses the Vercel AI SDK, NeuroLink's ContextEnricher reads the GenAI semantic-convention attributes that experimental_telemetry emits. NeuroLink itself has no dependency on the ai package — the imports below are your application's, and the SDK is not required to use NeuroLink:","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Vercel AI SDK Integration","lvl3":""}},
9110
- {"objectID":"744dacfc4f8a31928dda90d7c5abb025f178b286d2f7544c18f59ee242d5ea7d","title":"Environment Configuration","url":"/docs/observability/telemetry#environment-configuration","content":"`bash","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Environment Configuration","lvl3":""}},
9111
- {"objectID":"be7c8dc9c1ffb20410ecb524fb09eda288c482b7d2c71222ada9278c8437d280","title":"Enable telemetry","url":"/docs/observability/telemetry#enable-telemetry","content":"NEUROLINKTELEMETRYENABLED=true","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Enable telemetry","lvl3":""}},
9112
- {"objectID":"b4f80e93eb90dd4c4069c1f9fb4acfbb0496abf5dc6784d6e4994baed62a33d4","title":"OpenTelemetry endpoint (Jaeger, OTLP collector, etc.)","url":"/docs/observability/telemetry#opentelemetry-endpoint-jaeger-otlp-collector-etc","content":"OTELEXPORTEROTLP_ENDPOINT=http://localhost:4318","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"OpenTelemetry endpoint (Jaeger, OTLP collector, etc.)","lvl3":""}},
9113
- {"objectID":"5fd73c4b0b4c06ce5e6fabc8b88b576c4569063c9aee67a789515bf00c74ec46","title":"Service identification","url":"/docs/observability/telemetry#service-identification","content":"OTELSERVICENAME=my-ai-application\nOTELSERVICEVERSION=1.0.0","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Service identification","lvl3":""}},
9114
- {"objectID":"d07185ad040d87dd91afcf4a83e4a68d39cf48a31d488672ff6d7152d449df97","title":"Optional: Resource attributes","url":"/docs/observability/telemetry#optional-resource-attributes","content":"OTELRESOURCEATTRIBUTES=\"service.name=my-ai-app,service.version=1.0.0,deployment.environment=production\"","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Optional: Resource attributes","lvl3":""}},
9115
- {"objectID":"cae40a7cc527599e1bd741640e62f45cdf2503c5b0e99ea0a6b80dd9d4c1d2f4","title":"Optional: Sampling configuration","url":"/docs/observability/telemetry#optional-sampling-configuration","content":"OTELTRACESSAMPLER=traceidratio\nOTELTRACESSAMPLER_ARG=0.1 # Sample 10% of traces\n`","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Optional: Sampling configuration","lvl3":""}},
9116
- {"objectID":"3043ef1d5fa3c9cdc3f25bb1d2c4d5f3e650160b54e2b3af630105e58e61f560","title":"Environment Variables","url":"/docs/observability/telemetry#environment-variables","content":"| Variable | Description | Default |\n| ----------------------------- | ------------------------ | -------------- |\n| NEUROLINK_TELEMETRY_ENABLED | Enable/disable telemetry | false |\n| OTEL_EXPORTER_OTLP_ENDPOINT | OTLP endpoint URL | - |\n| OTEL_SERVICE_NAME | Service name | neurolink-ai |\n| OTEL_SERVICE_VERSION | Service version | 3.0.1 |","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Environment Variables","lvl3":""}},
9117
- {"objectID":"1196e9c4ad10ab88bcc4ee532ec941b2eebfe19b09eee44dafb9ee2d0b538e0b","title":"🔭 Proxy Telemetry (OTLP Triple-Signal Export)","url":"/docs/observability/telemetry#-proxy-telemetry-otlp-triple-signal-export","content":"When running the NeuroLink proxy (neurolink proxy start), OpenTelemetry is automatically initialized. If OTEL_EXPORTER_OTLP_ENDPOINT is set, the proxy exports three signal types via OTLP HTTP:\n\n| Signal | Endpoint | What it captures |\n| ------- | ----------------------------------------- | ------------------------------------------------------------------ |\n| Traces | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/traces | Per-request spans: receive → account selection → upstream → stream |\n| Metrics | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/metrics | Request counters, latency histograms, token usage gauges |\n| Logs | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/logs | Structured request log records with traceId/spanId correlation |\n\nConfiguration: Set OTEL_EXPORTER_OTLP_ENDPOINT (e.g., http://localhost:4318) before starting the proxy. The proxy defaults to service.name=neurolink-proxy.\n\nTrace correlation: Every JSONL request log entry includes traceId and spanId fields, enabling cross-signal correlation in backends like Jaeger, Grafana Tempo, or OpenObserve.\n\nCaller trace linkage: When a calling SDK already has an active trace, NeuroLink forwards W3C traceparent/tracestate headers and x-neurolink-session-id / x-neurolink-user-id / x-neurolink-conversation-id headers into the proxy so proxy spans can attach to the caller trace and preserve session-level attribution.\n\nTelemetryService reuse: If a global TracerProvider is already registered (e.g., by the host application), TelemetryService will reuse it instead of creating a duplicate — avoiding \"already registered\" errors.\n\nOpenObserve dashboard: The maintained proxy dashboard definition lives in docs/assets/dashboards/neurolink-proxy-observability-dashboard.json. For how to read that dashboard and which streams it should use, see Claude Proxy Observability.","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"🔭 Proxy Telemetry (OTLP Triple-Signal Export)","lvl3":""}},
9093
+ {"objectID":"94eeb9415209595c93b61952b4d4a2bca198440a69ba4ac78dbba15557cfb2e9","title":"Langfuse Integration","url":"/docs/observability/telemetry#langfuse-integration","content":"Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY and NeuroLink exports every AI operation to Langfuse. Pass observability: { langfuse: false } to disable. Full input and output are captured by default; use mask for sensitive data.\n\nIf your application already registers an OpenTelemetry TracerProvider, NeuroLink creates no provider but registers its Langfuse exporter when keys are configured; add createExporterSpanProcessor() to your provider (recommended), or add new LangfuseSpanProcessor() from @langfuse/otel with its own keys (no custom filter is needed because every NeuroLink observation span carries gen_ai.observation.type and infrastructure spans are not exported; NeuroLink's mask, chunking and retry do not apply to it). In serverless, call flushOpenTelemetry() before exit.\n\nThe full guide, including the migration table for removed fields and exports, is Observability.","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Langfuse Integration","lvl3":""}},
9094
+ {"objectID":"3043ef1d5fa3c9cdc3f25bb1d2c4d5f3e650160b54e2b3af630105e58e61f560","title":"Environment Variables","url":"/docs/observability/telemetry#environment-variables","content":"| Variable | Description | Default |\n| ----------------------------- | ---------------------------------------------------- | -------------- |\n| LANGFUSE_PUBLIC_KEY | Langfuse public key; with the secret key, enables it | - |\n| LANGFUSE_SECRET_KEY | Langfuse secret key | - |\n| LANGFUSE_BASE_URL | Langfuse host | Langfuse Cloud |\n| OTEL_EXPORTER_OTLP_ENDPOINT | OTLP collector endpoint for traces and metrics | - |\n| OTEL_SERVICE_NAME | Service name | neurolink-ai |","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Environment Variables","lvl3":""}},
9095
+ {"objectID":"1196e9c4ad10ab88bcc4ee532ec941b2eebfe19b09eee44dafb9ee2d0b538e0b","title":"🔭 Proxy Telemetry (OTLP Triple-Signal Export)","url":"/docs/observability/telemetry#-proxy-telemetry-otlp-triple-signal-export","content":"When running the NeuroLink proxy (neurolink proxy start), OpenTelemetry is automatically initialized. If OTEL_EXPORTER_OTLP_ENDPOINT is set, the proxy exports three signal types via OTLP HTTP:\n\n| Signal | Endpoint | What it captures |\n| ------- | ----------------------------------------- | ------------------------------------------------------------------ |\n| Traces | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/traces | Per-request spans: receive → account selection → upstream → stream |\n| Metrics | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/metrics | Request counters, latency histograms, token usage gauges |\n| Logs | $OTEL_EXPORTER_OTLP_ENDPOINT/v1/logs | Structured request log records with traceId/spanId correlation |\n\nConfiguration: Set OTEL_EXPORTER_OTLP_ENDPOINT (e.g., http://localhost:4318) before starting the proxy. The proxy defaults to service.name=neurolink-proxy.\n\nTrace correlation: Every JSONL request log entry includes traceId and spanId fields, enabling cross-signal correlation in backends like Jaeger, Grafana Tempo, or OpenObserve.\n\nCaller trace linkage: When a calling SDK already has an active trace, NeuroLink forwards W3C traceparent/tracestate headers and x-neurolink-session-id / x-neurolink-user-id / x-neurolink-conversation-id headers into the proxy so proxy spans can attach to the caller trace and preserve session-level attribution.\n\nProvider reuse: If a global TracerProvider is already registered (e.g., by the host application), NeuroLink registers nothing and uses it, avoiding \"already registered\" errors.\n\nOpenObserve dashboard: The maintained proxy dashboard definition lives in docs/assets/dashboards/neurolink-proxy-observability-dashboard.json. For how to read that dashboard and which streams it should use, see Claude Proxy Observability.","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"🔭 Proxy Telemetry (OTLP Triple-Signal Export)","lvl3":""}},
9118
9096
  {"objectID":"86edcd4d910e014c6ba3136e3beb5b3bac8acd20d33804cc1f315ce970a43458","title":"Local OpenObserve Setup For The Proxy","url":"/docs/observability/telemetry#local-openobserve-setup-for-the-proxy","content":"For a new local setup, use the repo-owned files in scripts/observability/ so the proxy dashboard does not depend on the Curator repo.\nOptional: copy scripts/observability/proxy-observability.env.example to scripts/observability/proxy-observability.env if the default ports or credentials clash with your machine.\nStart OpenObserve, start the OTEL collector, and import the dashboard:\nStart the proxy with the collector endpoint printed by the setup script. With the defaults, that is:\nOpen the UI at http://localhost:5080 and sign in with the configured OpenObserve credentials.\n\nUseful follow-up commands:\n\nWhen you are working from a local checkout instead of an installed CLI, pnpm run proxy:observability:* provides the same actions as repo shortcuts.\n\nWhat is machine-specific:\nOpenObserve URL, credentials, ports, container names, and volume names\nCompose project name if you intentionally run more than one local stack\nDashboard IDs and owners generated by OpenObserve when the dashboard is imported\n\nThe dashboard import helper strips dashboardId, owner, and created from the checked-in JSON before it calls the OpenObserve API, so those metadata fields do not need manual editing on a fresh machine.\n\nWhat is not machine-specific:\nThe dashboard query logic\nThe active streams neurolink_proxy and proxy_*\nThe proxy OTEL service name neurolink-proxy\nThe proxy log fields used for trace correlation and token analysis","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Local OpenObserve Setup For The Proxy","lvl3":""}},
9119
9097
  {"objectID":"1d93cd70de084c5782b6189b3f415762ac33859e4cc82b99e48b659deed9bfc5","title":"Proxy Log Conventions In OpenObserve","url":"/docs/observability/telemetry#proxy-log-conventions-in-openobserve","content":"Final request-summary rows are exported to the neurolink_proxy log stream and are the rows dashboard request panels should use.\nRaw body captures share that same log stream with event.name=proxy.body_capture, so log-backed request panels should filter to request-summary rows, for example http_method IS NOT NULL.\nPer-upstream-attempt diagnostics stay local in ~/.neurolink/logs/proxy-attempts-*.jsonl; they are useful for debugging retries but are intentionally not part of the main dashboard counts.\nAdditional proxy OTEL metrics may appear when relevant traffic exists, including model-substitution counters and response-body histograms alongside the cache, request, retry, duration, and cost metrics already used by the dashboard.","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Proxy Log Conventions In OpenObserve","lvl3":""}},
9120
9098
  {"objectID":"a941e8b4933de87676af26c7c7b094af2f5fed8891ab5253411454ecaade5eb1","title":"Docker Compose with Jaeger","url":"/docs/observability/telemetry#docker-compose-with-jaeger","content":"`yaml","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Docker Compose with Jaeger","lvl3":""}},
9121
- {"objectID":"46b6f7ef20460cd0dacd2baaf180207e7601172b87b53a1812d267a7beb740a9","title":"docker-compose.yml","url":"/docs/observability/telemetry#docker-composeyml","content":"version: \"3.8\"\nservices:\n my-ai-app:\n build: .\n environment:\nNEUROLINKTELEMETRYENABLED=true\nOTELEXPORTEROTLP_ENDPOINT=http://jaeger:14268/api/traces\nOTELSERVICENAME=my-ai-application\nOPENAIAPIKEY=${OPENAIAPIKEY}\n depends_on:\njaeger\n ports:\n\"3000:3000\"\n\n jaeger:\n image: jaegertracing/all-in-one:latest\n ports:\n\"16686:16686\" # Jaeger UI\n\"14268:14268\" # OTLP HTTP\n\"14250:14250\" # OTLP gRPC\n environment:\nCOLLECTOROTLPENABLED=true\nLOG_LEVEL=debug\n\n # Optional: Prometheus for metrics\n prometheus:\n image: prom/prometheus:latest\n ports:\n\"9090:9090\"\n volumes:\n./prometheus.yml:/etc/prometheus/prometheus.yml\n\n # Optional: Grafana for dashboards\n grafana:\n image: grafana/grafana:latest\n ports:\n\"3001:3000\"\n environment:\nGFSECURITYADMIN_PASSWORD=admin\n volumes:\ngrafana-storage:/var/lib/grafana\n\nvolumes:\n grafana-storage:\n`","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"docker-compose.yml","lvl3":""}},
9099
+ {"objectID":"46b6f7ef20460cd0dacd2baaf180207e7601172b87b53a1812d267a7beb740a9","title":"docker-compose.yml","url":"/docs/observability/telemetry#docker-composeyml","content":"version: \"3.8\"\nservices:\n my-ai-app:\n build: .\n environment:\nOTELEXPORTEROTLP_ENDPOINT=http://jaeger:14268/api/traces\nOTELSERVICENAME=my-ai-application\nOPENAIAPIKEY=${OPENAIAPIKEY}\n depends_on:\njaeger\n ports:\n\"3000:3000\"\n\n jaeger:\n image: jaegertracing/all-in-one:latest\n ports:\n\"16686:16686\" # Jaeger UI\n\"14268:14268\" # OTLP HTTP\n\"14250:14250\" # OTLP gRPC\n environment:\nCOLLECTOROTLPENABLED=true\nLOG_LEVEL=debug\n\n # Optional: Prometheus for metrics\n prometheus:\n image: prom/prometheus:latest\n ports:\n\"9090:9090\"\n volumes:\n./prometheus.yml:/etc/prometheus/prometheus.yml\n\n # Optional: Grafana for dashboards\n grafana:\n image: grafana/grafana:latest\n ports:\n\"3001:3000\"\n environment:\nGFSECURITYADMIN_PASSWORD=admin\n volumes:\ngrafana-storage:/var/lib/grafana\n\nvolumes:\n grafana-storage:\n`","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"docker-compose.yml","lvl3":""}},
9122
9100
  {"objectID":"7eb0866565462c132dd3cc9fa7c308f8ee6231bf6daf037b3dab796a9dd41d51","title":"AI Operation Metrics","url":"/docs/observability/telemetry#ai-operation-metrics","content":"Response Time: Time to generate AI responses\nToken Usage: Input/output tokens by provider and model\nCost Tracking: Estimated costs per operation\nError Rates: Failed AI requests by provider\nProvider Performance: Success rates and latency by provider","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"AI Operation Metrics","lvl3":""}},
9123
9101
  {"objectID":"bd59daf6ceed52988c126b5f4b9791a9dd59dc3af55dd54cee5fadadbcfa0a41","title":"Sample Prometheus Queries","url":"/docs/observability/telemetry#sample-prometheus-queries","content":"`promql","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Sample Prometheus Queries","lvl3":""}},
9124
9102
  {"objectID":"2195e6b74253e7286407019a6e35f118d73f417f08305ae56342b7918ea3cbfc","title":"Average AI response time over 5 minutes","url":"/docs/observability/telemetry#average-ai-response-time-over-5-minutes","content":"rate(neurolinkaidurationsum[5m]) / rate(neurolinkaidurationcount[5m])","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Average AI response time over 5 minutes","lvl3":""}},
@@ -9126,7 +9104,7 @@
9126
9104
  {"objectID":"4dc685e95bacb431f1aac9c03d1847bb23e3fd42be594f6069bd73467d987945","title":"Error rate percentage","url":"/docs/observability/telemetry#error-rate-percentage","content":"rate(neurolinkerrorstotal[5m]) / rate(neurolinkrequeststotal[5m]) * 100","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Error rate percentage","lvl3":""}},
9127
9105
  {"objectID":"b4a95233107d0262a770d1f2ebfa5c906f3700f2d54eaaf2666d3b88a0ed0e7d","title":"Cost per hour by provider","url":"/docs/observability/telemetry#cost-per-hour-by-provider","content":"sum by (provider) (rate(neurolinkcosttotal[1h]))","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Cost per hour by provider","lvl3":""}},
9128
9106
  {"objectID":"82637b90884727e0873ff8bf10b6b528e251e903be899387ef9e684a24fab5d9","title":"Active WebSocket connections","url":"/docs/observability/telemetry#active-websocket-connections","content":"neurolinkwebsocketconnections_active\n`","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"Active WebSocket connections","lvl3":""}},
9129
- {"objectID":"1901741e79f4b3ed72eae0c8765fd89ceac268e0540844b0ec8367c4a4131dc1","title":"✅ Quick Setup (5 minutes)","url":"/docs/observability/telemetry#-quick-setup-5-minutes","content":"Enable Telemetry\nStart Jaeger (Local Development)\nConfigure Endpoint\nInitialize in Code\nView Traces\nOpen http://localhost:16686\nGenerate some AI requests\nSearch for traces in Jaeger UI","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"✅ Quick Setup (5 minutes)","lvl3":""}},
9107
+ {"objectID":"1901741e79f4b3ed72eae0c8765fd89ceac268e0540844b0ec8367c4a4131dc1","title":"✅ Quick Setup (5 minutes)","url":"/docs/observability/telemetry#-quick-setup-5-minutes","content":"Set the service name\nStart Jaeger (Local Development)\nConfigure Endpoint\nRun your app\n\n Tracing starts with the first new NeuroLink(); no initialization call is needed.\nView Traces\nOpen http://localhost:16686\nGenerate some AI requests\nSearch for traces in Jaeger UI","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"✅ Quick Setup (5 minutes)","lvl3":""}},
9130
9108
  {"objectID":"790fed94c14846fea8574095e0237dcc2522ba7514f99d03d982c89d1ba6fbbf","title":"📚 Additional Resources","url":"/docs/observability/telemetry#-additional-resources","content":"API Reference - Complete telemetry API documentation\nReal-time Services - WebSocket infrastructure guide\nPerformance Optimization - Optimization strategies\n\nReady for enterprise-grade AI monitoring with NeuroLink! 📊","hierarchy":{"lvl0":"Observability","lvl1":"📊 Enterprise Telemetry Guide","lvl2":"📚 Additional Resources","lvl3":""}},
9131
9109
  {"objectID":"5122caad8c90eaa4c6454b2f4a4185aaee8933ab47a08806fad335486580d4df","title":"Migration Design: Remove AI SDK Google Dependencies","url":"/docs/plans/2026-01-01-remove-ai-sdk-google-design","content":"Migration Design: Remove AI SDK Google Dependencies\n\nDate: 2026-01-01\nBranch: feat/remove-ai-sdk-google\nStatus: Done — implemented in 076b9f4c3 (native @google/genai +\n@anthropic-ai/vertex-sdk). The Success Criteria below are all met.\n\nSummary\n\nRemove Vercel AI SDK wrappers (@ai-sdk/google, @ai-sdk/google-vertex) and migrate to the official unified Google SDK (@google/genai) for all Google AI Studio and Vertex AI Gemini models.\n\nMotivation\nReduce dependencies - Eliminate wrapper layer, use official SDK directly\nFuture-proof - @google-cloud/vertexai is deprecated (EOL June 2025); @google/genai is Google's recommended unified SDK\nConsistency - Native SDK path already exists for Gemini 3 with tools; extend pattern to all models\nBetter feature support - Direct access to thought_signature, extended thinking, and future Gemini features\n\nCurrent State Analysis\n\nDependencies to Remove\n\nDependencies to Keep\n\nProvider Files to Modify\n\n| File | Lines | Current Approach |\n| ------------------------------------- | ----- | ----------------------------------------- |\n| src/lib/providers/googleAiStudio.ts | ~1370 | AI SDK primary, native for Gemini 3+tools |\n| src/lib/providers/googleVertex.ts | ~3285 | AI SDK primary, native for Gemini 3+tools |\n\nArchitecture Design\n\nNew Unified Approach\n\nThe @google/genai SDK supports both authentication modes:\n\nStreaming Architecture\n\nReplace streamText() from AI SDK with native streaming:\n\nMessage Format Transformation\n\n| Vercel AI SDK Format | @google/genai Format |\n| ----------------------------------------------------- | ------------------------------------- |\n| { role: \"user\", content: [{ type: \"text\", text }] } | { role: \"user\", parts: [{ text }] } |\n| { type: \"image\", image: Buffer } | { inlineData: { mimeType, data } } |\n| { type: \"file\", data: Buffer } | { fileData: { mimeType, fileUri } } |\n\nTool Format Transformation\n\n| Vercel AI SDK Tool | @google/genai FunctionDeclaration |\n| -------------------------------------- | --------------------------------------------- |\n| { description, parameters, execute } | { name, description, parametersJsonSchema } |\n\nImplementation Plan\n\nPhase 1: Google AI Studio Provider (googleAiStudio.ts)\n\nStep 1.1: Remove AI SDK imports\n\nStep 1.2: Replace getAISDKModel() with native client\n\nStep 1.3: Convert message building\nAdd new convertToGoogleContents() method\nTransform CoreMessage[] to Content[] (Google format)\nHandle multimodal parts (text, images, PDFs)\n\nStep 1.4: Replace streaming implementation\nUse existing executeNativeGemini3Stream() as template\nRemove model detection logic (all models use native now)\nImplement unified streaming for all Gemini models\n\nStep 1.5: Replace generation implementation\nUse existing executeNativeGemini3Generate() as template\nExtend to all models\n\nPhase 2: Google Vertex Provider (googleVertex.ts)\n\nStep 2.1: Remove AI SDK imports\n\nNote: Anthropic Claude models via Vertex will still use @ai-sdk/google-vertex/anthropic since that's a separate API.\n\nStep 2.2: Replace Gemini model creation\n\nStep 2.3: Dual architecture\nKeep createVertexAnthropic() for Claude models\nUse @google/genai for all Gemini models\n\nStep 2.4: Unify streaming/generation paths\nReuse patterns from Google AI Studio\nHandle Vertex-specific authentication\n\nPhase 3: BaseProvider Updates\n\nStep 3.1: Update abstract methods\n\nStep 3.2: Make getAISDKModel() optional or provider-specific\nNon-Google providers still use AI SDK\nGoogle providers use native SDK directly\n\nPhase 4: Test Updates\n\nStep 4.1: Update test/setup.ts mocks\n\nStep 4.2: Update unit tests\ntest/unit/models/gemini-3-flash.test.ts\ntest/unit/thinking/thinking-configuration.test.ts\ntest/unit/providers/factory.test.ts\n\nStep 4.3: Run integration tests\n\nKey Transformations\nMessage Content Transformation\nTool Transformation\nThinking Configuration\n\nBackward Compatibility\n\nNo Breaking API Changes\nSDK public interface (neurolink.stream(), neurolink.generate()) unchanged\nCLI commands unchanged\nConfiguration unchanged\n\nInternal-Only Changes\nProvider implementation details\nSDK dependency swap\nTest mocks\n\nRisk Mitigation\n\n| Risk | Mitigation |\n| --------------------------- | ---------------------------------------------------------- |\n| Native SDK missing features | Existing Gemini 3 native implementation proves feasibility |\n| Test breakage | Comprehensive test suite with known patterns |\n| Authentication differences | @google/genai supports both API key and Vertex auth |\n| Performance regression | Native SDK eliminates wrapper overhead |\n\nTesting Strategy\nUnit Tests\nIntegration Tests\nEnd-to-End Tests\nManual Validation\n\nSuccess Criteria\n✅ @ai-sdk/google and @ai-sdk/google-vertex removed from package.json\n✅ Al","hierarchy":{"lvl0":"Plans","lvl1":"Migration Design: Remove AI SDK Google Dependencies","lvl2":"","lvl3":""}},
9132
9110
  {"objectID":"f22a2e266bd83093ebf4cc0b4fc75522e7ee728a0564d9d2f60d51bfbd6c3868","title":"Migration Design: Remove AI SDK Google Dependencies","url":"/docs/plans/2026-01-01-remove-ai-sdk-google-design#migration-design-remove-ai-sdk-google-dependencies","content":"Date: 2026-01-01\nBranch: feat/remove-ai-sdk-google\nStatus: Done — implemented in 076b9f4c3 (native @google/genai +\n@anthropic-ai/vertex-sdk). The Success Criteria below are all met.","hierarchy":{"lvl0":"Plans","lvl1":"Migration Design: Remove AI SDK Google Dependencies","lvl2":"Migration Design: Remove AI SDK Google Dependencies","lvl3":""}},
@@ -9312,11 +9290,11 @@
9312
9290
  {"objectID":"2edb91c487b804890ddf44bbc51f4666b33b4c32d89b02883154e5bcf98fe2af","title":"Running Examples Locally","url":"/docs/playground#running-examples-locally","content":"Clone the full NeuroLink repository and run the demo project:","hierarchy":{"lvl0":"Playground","lvl1":"Interactive Playground","lvl2":"Running Examples Locally","lvl3":""}},
9313
9291
  {"objectID":"b3bb65104008aaf85abba83803036fffd077b778f4e842217e31ab6995b58662","title":"Playground Features","url":"/docs/playground#playground-features","content":"All examples include:\nZero Configuration - Pre-configured with sensible defaults\nTypeScript Support - Full type safety out of the box\nHot Reload - Instant feedback as you code\nEnvironment Setup - .env.example files for easy API key configuration\nModern Stack - Built with Vite, TypeScript, and modern tooling\nCommented Code - Detailed inline documentation explaining key concepts","hierarchy":{"lvl0":"Playground","lvl1":"Interactive Playground","lvl2":"Playground Features","lvl3":""}},
9314
9292
  {"objectID":"eae04fd1f2877372e6e05fd584e8f33401e52de898d32676e764ff0e47e1a566","title":"Need Help?","url":"/docs/playground#need-help","content":"Documentation: Getting Started Guide\nExamples: SDK Examples\nSupport: GitHub Issues\nCommunity: GitHub Discussions","hierarchy":{"lvl0":"Playground","lvl1":"Interactive Playground","lvl2":"Need Help?","lvl3":""}},
9315
- {"objectID":"78ffd9331e1d9c4d641839b9fc93ad64462fe345988a046744a20cc1dd49833b","title":"00 · Native Provider Architecture","url":"/docs/provider-integration/00-architecture","content":"00 · Native Provider Architecture\n\nStart a new integration at Provider Onboarding Tiers. This\npage describes the current runtime; the original SDK-wrapper implementation\nremains in git history at c829f4de. NeuroLink no longer depends on the Vercel\nai or @ai-sdk/* packages.\n\nChoose the integration boundary\n\n| Situation | Implementation |\n| ------------------------------------------------------------------- | ------------------------------------------------------------------------------ |\n| Model already available through an existing aggregator | Tier 1: configure its model ID |\n| Standard OpenAI chat-completions protocol without behavioral quirks | Tier 2: src/lib/providers/catalog/<id>.json, then pnpm run codegen:catalog |\n| OpenAI-compatible transport with request or error quirks | Extend OpenAIChatCompletionsProvider and override the relevant hooks |\n| Native SDK, signing, or nonstandard lifecycle | Follow the Tier 3 or Tier 4 guide; preserve both public generation modes |\n\nCatalog entries generate metadata; do not separately hand-edit generated enums,\ncredential keys, or provider choices. Native providers remain registered using\ndynamic imports inside factory functions in providerRegistry.ts.\n\nGenerate and stream are distinct paths\n\nFor the OpenAI-compatible family:\ngenerate() runs runNativeGenerateLoop over the provider's doGenerate.\n The ordinary wire request is JSON, not SSE; provider-specific streaming-wire\n exceptions stay inside the delegating model.\nstream() drives the native HTTP/SSE loop in executeStream. It emits\n incremental content and reasoning, executes tool calls, and exposes usage.\nBoth modes must preserve credentials, abort signals, timeouts, tool-name\n mapping, request repair, fallback policy, and structured-output behavior.\n A passing stream test does not prove the non-streaming request body.\n\nThe internal names getAISDKModel and LanguageModelV3 remain compatibility\nnames. Their implementations and types are local to NeuroLink; they do not\nimply a dependency on the Vercel SDK. A method-shaped doStream member alone\nis not proof that a model handle can stream: test the call itself.\n\nShared OpenAI-compatible hooks\n\nThe base lives in src/lib/providers/openaiChatCompletionsBase.ts and shares\nwire helpers from openaiChatCompletionsClient.ts. Subclasses should customize\nthese hooks rather than duplicate the full generation pipeline.\n\n| Hook | Responsibility |\n| ----------------------------------------- | --------------------------------------------------------- |\n| getProviderName, getDefaultModel | Provider identity and default model |\n| formatProviderError | Return a classified error; never throw from the formatter |\n| getChatCompletionsURL, getAuthHeaders | Endpoint and authentication variations |\n| adjustBuildBodyOptions | Sampling changes and the extraBody channel |\n| adjustRequestBody(body, modelId) | Final provider-specific wire-body transformation |\n| adjustResponseFormat | Structured-output format changes |\n| adjustBodyAfter400 | One corrected retry for a recognized bad request |\n| getFallbackModels | Alternatives for unavailable model IDs |\n| onStreamStart | Provider-specific streaming lifecycle instrumentation |\n| validateConfiguration | Provider configuration/reachability validation |\n\nExamples: DeepSeek downgrades json_schema to json_object;\nNVIDIA NIM sends native extra fields and repairs specific\n400 responses; LM Studio and llama.cpp\nprovide local model discovery and friendly connection errors.\n\nCredentials and proxy support\n\nCredentials flow through NeuroLink → provider factory → registry → provider\nconstructor. Precedence is per-call credentials, instance credentials, then\nenvironment defaults. Exact handling of blank values is provider-specific;\ncopy the neighboring implementation rather than inventing a second resolver.\nThe OpenAI-compatible base obtains corporate-proxy support from\ncreateProxyFetch().\n\nDo not print keys or credential-bearing URLs. Use the existing log-redaction\nhelpers. Local backends may use placeholder bearer keys; a reverse proxy can\nrequire real credentials, so preserve explicit overrides.\n\nTypes and public surfaces\n\nUse named exports and type, not interface. Keep shared types in\nsrc/lib/types/ with unique names, importing internal types through its barrel.\nDo not use double assertions to conceal an incompatible model shape.\n\nKeep existing public signatures work","hierarchy":{"lvl0":"Provider Integration","lvl1":"00 · Native Provider Architecture","lvl2":"","lvl3":""}},
9293
+ {"objectID":"78ffd9331e1d9c4d641839b9fc93ad64462fe345988a046744a20cc1dd49833b","title":"00 · Native Provider Architecture","url":"/docs/provider-integration/00-architecture","content":"00 · Native Provider Architecture\n\nStart a new integration at Provider Onboarding Tiers. This\npage describes the current runtime; the original SDK-wrapper implementation\nremains in git history at c829f4de. NeuroLink no longer depends on the Vercel\nai or @ai-sdk/* packages.\n\nChoose the integration boundary\n\n| Situation | Implementation |\n| ------------------------------------------------------------------- | ------------------------------------------------------------------------------ |\n| Model already available through an existing aggregator | Tier 1: configure its model ID |\n| Standard OpenAI chat-completions protocol without behavioral quirks | Tier 2: src/lib/providers/catalog/<id>.json, then pnpm run codegen:catalog |\n| OpenAI-compatible transport with request or error quirks | Extend OpenAIChatCompletionsProvider and override the relevant hooks |\n| Native SDK, signing, or nonstandard lifecycle | Follow the Tier 3 or Tier 4 guide; preserve both public generation modes |\n\nCatalog entries generate metadata; do not separately hand-edit generated enums,\ncredential keys, or provider choices. Native providers remain registered using\ndynamic imports inside factory functions in providerRegistry.ts.\n\nGenerate and stream are distinct paths\n\nFor the OpenAI-compatible family:\ngenerate() runs runNativeGenerateLoop over the provider's doGenerate.\n The ordinary wire request is JSON, not SSE; provider-specific streaming-wire\n exceptions stay inside the delegating model.\nstream() drives the native HTTP/SSE loop in executeStream. It emits\n incremental content and reasoning, executes tool calls, and exposes usage.\nBoth modes must preserve credentials, abort signals, timeouts, tool-name\n mapping, request repair, fallback policy, and structured-output behavior.\n A passing stream test does not prove the non-streaming request body.\n\nThe internal names getAISDKModel and LanguageModelV3 remain compatibility\nnames. Their implementations and types are local to NeuroLink; they do not\nimply a dependency on the Vercel SDK. A method-shaped doStream member alone\nis not proof that a model handle can stream: test the call itself.\n\nShared OpenAI-compatible hooks\n\nThe base lives in src/lib/providers/openaiChatCompletionsBase.ts and shares\nwire helpers from openaiChatCompletionsClient.ts. Subclasses should customize\nthese hooks rather than duplicate the full generation pipeline.\n\n| Hook | Responsibility |\n| ----------------------------------------- | --------------------------------------------------------- |\n| getProviderName, getDefaultModel | Provider identity and default model |\n| formatProviderError | Return a classified error; never throw from the formatter |\n| getChatCompletionsURL, getAuthHeaders | Endpoint and authentication variations |\n| adjustBuildBodyOptions | Sampling changes and the extraBody channel |\n| adjustRequestBody(body, modelId) | Final provider-specific wire-body transformation |\n| adjustResponseFormat | Structured-output format changes |\n| adjustBodyAfter400 | One corrected retry for a recognized bad request |\n| getFallbackModels | Alternatives for unavailable model IDs |\n| validateConfiguration | Provider configuration/reachability validation |\n\nExamples: DeepSeek downgrades json_schema to json_object;\nNVIDIA NIM sends native extra fields and repairs specific\n400 responses; LM Studio and llama.cpp\nprovide local model discovery and friendly connection errors.\n\nCredentials and proxy support\n\nCredentials flow through NeuroLink → provider factory → registry → provider\nconstructor. Precedence is per-call credentials, instance credentials, then\nenvironment defaults. Exact handling of blank values is provider-specific;\ncopy the neighboring implementation rather than inventing a second resolver.\nThe OpenAI-compatible base obtains corporate-proxy support from\ncreateProxyFetch().\n\nDo not print keys or credential-bearing URLs. Use the existing log-redaction\nhelpers. Local backends may use placeholder bearer keys; a reverse proxy can\nrequire real credentials, so preserve explicit overrides.\n\nTypes and public surfaces\n\nUse named exports and type, not interface. Keep shared types in\nsrc/lib/types/ with unique names, importing internal types through its barrel.\nDo not use double assertions to conceal an incompatible model shape.\n\nKeep existing public signatures working. Changes to browser factories, client\nadapters, generated declarations, and lifecycle callbacks need","hierarchy":{"lvl0":"Provider Integration","lvl1":"00 · Native Provider Architecture","lvl2":"","lvl3":""}},
9316
9294
  {"objectID":"a25de4bd894e0b51da90c7f860305f722f7b4d35675d84cafa174a9f6ff00357","title":"00 · Native Provider Architecture","url":"/docs/provider-integration/00-architecture#00-native-provider-architecture","content":"Start a new integration at Provider Onboarding Tiers. This\npage describes the current runtime; the original SDK-wrapper implementation\nremains in git history at c829f4de. NeuroLink no longer depends on the Vercel\nai or @ai-sdk/* packages.","hierarchy":{"lvl0":"Provider Integration","lvl1":"00 · Native Provider Architecture","lvl2":"00 · Native Provider Architecture","lvl3":""}},
9317
9295
  {"objectID":"b2985c13261fa182f361d4f3637f38ce364c25aa7dab4e2916b4f82e74665389","title":"Choose the integration boundary","url":"/docs/provider-integration/00-architecture#choose-the-integration-boundary","content":"| Situation | Implementation |\n| ------------------------------------------------------------------- | ------------------------------------------------------------------------------ |\n| Model already available through an existing aggregator | Tier 1: configure its model ID |\n| Standard OpenAI chat-completions protocol without behavioral quirks | Tier 2: src/lib/providers/catalog/<id>.json, then pnpm run codegen:catalog |\n| OpenAI-compatible transport with request or error quirks | Extend OpenAIChatCompletionsProvider and override the relevant hooks |\n| Native SDK, signing, or nonstandard lifecycle | Follow the Tier 3 or Tier 4 guide; preserve both public generation modes |\n\nCatalog entries generate metadata; do not separately hand-edit generated enums,\ncredential keys, or provider choices. Native providers remain registered using\ndynamic imports inside factory functions in providerRegistry.ts.","hierarchy":{"lvl0":"Provider Integration","lvl1":"00 · Native Provider Architecture","lvl2":"Choose the integration boundary","lvl3":""}},
9318
9296
  {"objectID":"b8ff68813a93cbef304867f6b74521287a4fdd9bb3c0a66ac4afec5ce2b8af5c","title":"Generate and stream are distinct paths","url":"/docs/provider-integration/00-architecture#generate-and-stream-are-distinct-paths","content":"For the OpenAI-compatible family:\ngenerate() runs runNativeGenerateLoop over the provider's doGenerate.\n The ordinary wire request is JSON, not SSE; provider-specific streaming-wire\n exceptions stay inside the delegating model.\nstream() drives the native HTTP/SSE loop in executeStream. It emits\n incremental content and reasoning, executes tool calls, and exposes usage.\nBoth modes must preserve credentials, abort signals, timeouts, tool-name\n mapping, request repair, fallback policy, and structured-output behavior.\n A passing stream test does not prove the non-streaming request body.\n\nThe internal names getAISDKModel and LanguageModelV3 remain compatibility\nnames. Their implementations and types are local to NeuroLink; they do not\nimply a dependency on the Vercel SDK. A method-shaped doStream member alone\nis not proof that a model handle can stream: test the call itself.","hierarchy":{"lvl0":"Provider Integration","lvl1":"00 · Native Provider Architecture","lvl2":"Generate and stream are distinct paths","lvl3":""}},
9319
- {"objectID":"48acc7bdd72dc7e80e6598482f9b95958debdad76802027aea8f2114cd83f075","title":"Shared OpenAI-compatible hooks","url":"/docs/provider-integration/00-architecture#shared-openai-compatible-hooks","content":"The base lives in src/lib/providers/openaiChatCompletionsBase.ts and shares\nwire helpers from openaiChatCompletionsClient.ts. Subclasses should customize\nthese hooks rather than duplicate the full generation pipeline.\n\n| Hook | Responsibility |\n| ----------------------------------------- | --------------------------------------------------------- |\n| getProviderName, getDefaultModel | Provider identity and default model |\n| formatProviderError | Return a classified error; never throw from the formatter |\n| getChatCompletionsURL, getAuthHeaders | Endpoint and authentication variations |\n| adjustBuildBodyOptions | Sampling changes and the extraBody channel |\n| adjustRequestBody(body, modelId) | Final provider-specific wire-body transformation |\n| adjustResponseFormat | Structured-output format changes |\n| adjustBodyAfter400 | One corrected retry for a recognized bad request |\n| getFallbackModels | Alternatives for unavailable model IDs |\n| onStreamStart | Provider-specific streaming lifecycle instrumentation |\n| validateConfiguration | Provider configuration/reachability validation |\n\nExamples: DeepSeek downgrades json_schema to json_object;\nNVIDIA NIM sends native extra fields and repairs specific\n400 responses; LM Studio and llama.cpp\nprovide local model discovery and friendly connection errors.","hierarchy":{"lvl0":"Provider Integration","lvl1":"00 · Native Provider Architecture","lvl2":"Shared OpenAI-compatible hooks","lvl3":""}},
9297
+ {"objectID":"48acc7bdd72dc7e80e6598482f9b95958debdad76802027aea8f2114cd83f075","title":"Shared OpenAI-compatible hooks","url":"/docs/provider-integration/00-architecture#shared-openai-compatible-hooks","content":"The base lives in src/lib/providers/openaiChatCompletionsBase.ts and shares\nwire helpers from openaiChatCompletionsClient.ts. Subclasses should customize\nthese hooks rather than duplicate the full generation pipeline.\n\n| Hook | Responsibility |\n| ----------------------------------------- | --------------------------------------------------------- |\n| getProviderName, getDefaultModel | Provider identity and default model |\n| formatProviderError | Return a classified error; never throw from the formatter |\n| getChatCompletionsURL, getAuthHeaders | Endpoint and authentication variations |\n| adjustBuildBodyOptions | Sampling changes and the extraBody channel |\n| adjustRequestBody(body, modelId) | Final provider-specific wire-body transformation |\n| adjustResponseFormat | Structured-output format changes |\n| adjustBodyAfter400 | One corrected retry for a recognized bad request |\n| getFallbackModels | Alternatives for unavailable model IDs |\n| validateConfiguration | Provider configuration/reachability validation |\n\nExamples: DeepSeek downgrades json_schema to json_object;\nNVIDIA NIM sends native extra fields and repairs specific\n400 responses; LM Studio and llama.cpp\nprovide local model discovery and friendly connection errors.","hierarchy":{"lvl0":"Provider Integration","lvl1":"00 · Native Provider Architecture","lvl2":"Shared OpenAI-compatible hooks","lvl3":""}},
9320
9298
  {"objectID":"21368995ed7311c991929d1723e3acf1df7a3bb8fd1f00ea3b1b9b92e63a971a","title":"Credentials and proxy support","url":"/docs/provider-integration/00-architecture#credentials-and-proxy-support","content":"Credentials flow through NeuroLink → provider factory → registry → provider\nconstructor. Precedence is per-call credentials, instance credentials, then\nenvironment defaults. Exact handling of blank values is provider-specific;\ncopy the neighboring implementation rather than inventing a second resolver.\nThe OpenAI-compatible base obtains corporate-proxy support from\ncreateProxyFetch().\n\nDo not print keys or credential-bearing URLs. Use the existing log-redaction\nhelpers. Local backends may use placeholder bearer keys; a reverse proxy can\nrequire real credentials, so preserve explicit overrides.","hierarchy":{"lvl0":"Provider Integration","lvl1":"00 · Native Provider Architecture","lvl2":"Credentials and proxy support","lvl3":""}},
9321
9299
  {"objectID":"718e4a52f84829ee627fbc0311723489e097f33d3b04de9d469bb70ba0fd994a","title":"Types and public surfaces","url":"/docs/provider-integration/00-architecture#types-and-public-surfaces","content":"Use named exports and type, not interface. Keep shared types in\nsrc/lib/types/ with unique names, importing internal types through its barrel.\nDo not use double assertions to conceal an incompatible model shape.\n\nKeep existing public signatures working. Changes to browser factories, client\nadapters, generated declarations, and lifecycle callbacks need their own\nconsumer-boundary checks; a provider HTTP test does not cover those surfaces.","hierarchy":{"lvl0":"Provider Integration","lvl1":"00 · Native Provider Architecture","lvl2":"Types and public surfaces","lvl3":""}},
9322
9300
  {"objectID":"b25100877d71a2e6af9f534b1034e1a6404a5514532bb3c47bba18a5b327fb6e","title":"Verification","url":"/docs/provider-integration/00-architecture#verification","content":"Build first, then use the shipped SDK/CLI, not a second source module graph.\nAt minimum exercise both modes for plain text, tools, error propagation,\nabort/timeout, and any provider-specific schema behavior. Assert that a mock\nserver actually received the request before claiming a network-side effect.\n\nUseful commands:\n\nThe first contract suites use deterministic stand-ins; the new-provider suite\nalso needs live credentials or local servers for relevant cases. Report skips\nand unavailable endpoints separately from passes. The live matrix complements\nwire-level tests; it cannot establish every branch on its own.","hierarchy":{"lvl0":"Provider Integration","lvl1":"00 · Native Provider Architecture","lvl2":"Verification","lvl3":""}},
@@ -9473,10 +9451,10 @@
9473
9451
  {"objectID":"d6369ff4884b24de9908933128fae325b09b5d0c5f1da0e0680c92d2e69ad3be","title":"3. Abort Signal Stream (lm-studio, llamacpp context)","url":"/docs/provider-integration/11-test-failure-investigation#3-abort-signal-stream-lm-studio-llamacpp-context","content":"Was: \"Stream context exceeds model budget and no compaction is possible. Estimated: 6387 tokens, budget: 0 tokens.\"\n\nRoot cause: The Budget=0 bug we already fixed in 12 test files (test sets maxTokens = PROVIDER_MAX_TOKENS[provider] || 8192, which equaled the local model's full context window → 0 input budget). The fix applied to continuous-test-suite-context.ts.\n\nVerification: Direct stream test with disableTools: true — PASS, 2 chunks received before abort. With my context.ts fix (maxTokens fallback 8192→1024, plus new providers added), the in-suite test should also pass when LM Studio server is up.\n\nStatus: ✅ FIXED. Same Budget=0 fix that fixed memory tests.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Investigation: 4 Real Sub-Test Failures Drilled","lvl2":"3. Abort Signal Stream (lm-studio, llamacpp context)","lvl3":""}},
9474
9452
  {"objectID":"fe3ab8308de03a601560d9fb79a44fd6f15ad9f811e1466ecbad47ad1dbb9b05","title":"4. Cross-provider Observability Spans (deepseek, lm-studio, llamacpp via providers suite)","url":"/docs/provider-integration/11-test-failure-investigation#4-cross-provider-observability-spans-deepseek-lm-studio-llamacpp-via-providers-suite","content":"Was: \"generate() succeeded but no model.generation spans found\"\n\nRoot cause: OpenAI-compat providers (DeepSeek, NIM, LM Studio, llama.cpp, plus existing OpenAI/LiteLLM/etc) intentionally skip Pipeline B span emission to avoid duplicate Langfuse observations. They use Pipeline A (AI SDK + Langfuse OTEL). The test only validated Pipeline B, so any provider on Pipeline A failed.\n\nFix shipped: the test now SKIPs only when the running provider is on the Pipeline A allowlist (the OpenAI-compat set listed above; spans are emitted via the AI SDK + Langfuse OTEL path elsewhere). For native (Pipeline B) providers — Bedrock, Ollama, native Gemini 3 — a missing model.generation span continues to FAIL the test, since those providers are expected to emit it themselves. The allowlist tracks the comment in neurolink.ts:initializeMetricsListeners().\n\nStatus: ✅ FIXED in test/continuous-test-suite-providers.ts.","hierarchy":{"lvl0":"Provider Integration","lvl1":"Investigation: 4 Real Sub-Test Failures Drilled","lvl2":"4. Cross-provider Observability Spans (deepseek, lm-studio, llamacpp via providers suite)","lvl3":""}},
9475
9453
  {"objectID":"63ce4d83bfd386e8bf9e1d797c5e1c04d1c10ec51613dac7716bef8a6b07c238","title":"Summary","url":"/docs/provider-integration/11-test-failure-investigation#summary","content":"All 4 of the \"real test failures\" were:\n2 real test bugs: prompt design (RAGAS), Pipeline A skip (Observability Spans)\n1 environment: LM Studio server crashed/idle-timed-out between iterations\n1 same root cause as the Budget=0 fallback bug (Bug 3 in this document): a stream test hit the same PROVIDER_MAX_TOKENS || 8192 fallback issue already fixed in iter12.\n\nCombined with the 10 infrastructure bugs found and fixed across iterations 5-13, no real provider-integration bugs remain. The remaining \"failures\" in the matrix logs are:\nCells where LM Studio server was offline (need server-keep-alive policy)\nCells timed out at 600-900s gtimeout because local models do 15 multi-turn tests slowly (need 1200s+ timeout)\nCross-provider tests that exercise Vertex/Anthropic/Bedrock/OpenRouter without their credentials (env, not test target)","hierarchy":{"lvl0":"Provider Integration","lvl1":"Investigation: 4 Real Sub-Test Failures Drilled","lvl2":"Summary","lvl3":""}},
9476
- {"objectID":"ef073a7d56f556b336eba636cd634ac3f4ffbc593cb1ab22716c2fe5266c7e5e","title":"PR Analysis & Commit Plan","url":"/docs/provider-integration/12-pr-analysis","content":"PR Analysis & Commit Plan\n\nWhat the PR contains\n\nTotal scope\n28 modified files (existing core files updated)\n6 new file groups (4 new provider files + 1 test suite + 1 shell script + docs/)\n~700 insertions, ~80 deletions in modified files\n~1000 LOC in new provider files\n~870 LOC in new test file\n13 new Markdown docs (~150KB)\n\nRisk level: medium\nTouches public SDK API (new providers visible at runtime via the AIProviderName.DEEPSEEK constant or the string id \"deepseek\", etc.)\nModifies shared pricing logic (pricing.ts _default fallback) — could affect other providers\nModifies 12 test suite files (changes shared PROVIDER_MAX_TOKENS map and fallback)\nTest changes are backwards-compatible — same tests pass for existing providers\n\nFiles to commit\n\nA. New provider implementations (4 files, ~1000 LOC)\n\nAll four:\nExtend BaseProvider\nUse createOpenAI(...).chat() for /v1/chat/completions endpoint (NOT /v1/responses)\nWrap streamText with withClientStreamSpan for OTEL tracing (NOT withClientSpan — that ends the span when the callback returns, before the iterable is consumed; for streaming use the *StreamSpan variant that wraps the returned iterable)\nEmit neurolink.provider.stream span with proper gen_ai.* attrs\nUse makeLoggingFetch to capture upstream non-2xx response bodies\nImplement all 5 BaseProvider abstract methods (executeStream, getProviderName, getDefaultModel, getAISDKModel, formatProviderError)\n\nB. Core integration changes (10 modified files)\n\n| File | Change |\n| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| src/lib/factories/providerRegistry.ts | 4 dynamic-import registrations (per CLAUDE.md rule #1) |\n| src/lib/types/providers.ts | NeurolinkCredentials extended + new NvidiaNimExtraBody type |\n| src/lib/constants/enums.ts | AIProviderName enum + 4 model enums |\n| src/lib/constants/contextWindows.ts | 4 sections with model context windows |\n| src/lib/utils/pricing.ts | 4 entries + _default sentinel as provider-level fallback. Local providers (lm-studio / llamacpp) _default rates are 0 (no upstream USD price) and hasPricing() returns false for zero-rate entries so callers correctly treat them as non-billable. |\n| src/lib/utils/providerConfig.ts | 4 createXConfig helpers |\n| src/lib/utils/modelChoices.ts | TOP_MODELS_CONFIG + MODEL_ENUMS entries |\n| src/lib/adapters/providerImageAdapter.ts | VISION_CAPABILITIES (vision unsupported) |\n| src/cli/factories/commandFactory.ts | provider choices in 3 spots |\n| src/lib/providers/index.ts | barrel exports ","hierarchy":{"lvl0":"Provider Integration","lvl1":"PR Analysis & Commit Plan","lvl2":"","lvl3":""}},
9454
+ {"objectID":"ef073a7d56f556b336eba636cd634ac3f4ffbc593cb1ab22716c2fe5266c7e5e","title":"PR Analysis & Commit Plan","url":"/docs/provider-integration/12-pr-analysis","content":"PR Analysis & Commit Plan\n\nWhat the PR contains\n\nTotal scope\n28 modified files (existing core files updated)\n6 new file groups (4 new provider files + 1 test suite + 1 shell script + docs/)\n~700 insertions, ~80 deletions in modified files\n~1000 LOC in new provider files\n~870 LOC in new test file\n13 new Markdown docs (~150KB)\n\nRisk level: medium\nTouches public SDK API (new providers visible at runtime via the AIProviderName.DEEPSEEK constant or the string id \"deepseek\", etc.)\nModifies shared pricing logic (pricing.ts _default fallback) — could affect other providers\nModifies 12 test suite files (changes shared PROVIDER_MAX_TOKENS map and fallback)\nTest changes are backwards-compatible — same tests pass for existing providers\n\nFiles to commit\n\nA. New provider implementations (4 files, ~1000 LOC)\n\nAll four:\nExtend BaseProvider\nUse createOpenAI(...).chat() for /v1/chat/completions endpoint (NOT /v1/responses)\nWrap streamText with withClientStreamSpan for OTEL tracing (NOT withClientSpan — that ends the span when the callback returns, before the iterable is consumed; for streaming use the *StreamSpan variant that wraps the returned iterable)\nEmit provider.stream span with proper gen_ai.* attrs\nUse makeLoggingFetch to capture upstream non-2xx response bodies\nImplement all 5 BaseProvider abstract methods (executeStream, getProviderName, getDefaultModel, getAISDKModel, formatProviderError)\n\nB. Core integration changes (10 modified files)\n\n| File | Change |\n| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| src/lib/factories/providerRegistry.ts | 4 dynamic-import registrations (per CLAUDE.md rule #1) |\n| src/lib/types/providers.ts | NeurolinkCredentials extended + new NvidiaNimExtraBody type |\n| src/lib/constants/enums.ts | AIProviderName enum + 4 model enums |\n| src/lib/constants/contextWindows.ts | 4 sections with model context windows |\n| src/lib/utils/pricing.ts | 4 entries + _default sentinel as provider-level fallback. Local providers (lm-studio / llamacpp) _default rates are 0 (no upstream USD price) and hasPricing() returns false for zero-rate entries so callers correctly treat them as non-billable. |\n| src/lib/utils/providerConfig.ts | 4 createXConfig helpers |\n| src/lib/utils/modelChoices.ts | TOP_MODELS_CONFIG + MODEL_ENUMS entries |\n| src/lib/adapters/providerImageAdapter.ts | VISION_CAPABILITIES (vision unsupported) |\n| src/cli/factories/commandFactory.ts | provider choices in 3 spots |\n| src/lib/providers/index.ts | barrel exports ","hierarchy":{"lvl0":"Provider Integration","lvl1":"PR Analysis & Commit Plan","lvl2":"","lvl3":""}},
9477
9455
  {"objectID":"7531988e2a5d2a88439710b5048e45aa550bec5148b60220f6cf8a3c450a74db","title":"Total scope","url":"/docs/provider-integration/12-pr-analysis#total-scope","content":"28 modified files (existing core files updated)\n6 new file groups (4 new provider files + 1 test suite + 1 shell script + docs/)\n~700 insertions, ~80 deletions in modified files\n~1000 LOC in new provider files\n~870 LOC in new test file\n13 new Markdown docs (~150KB)","hierarchy":{"lvl0":"Provider Integration","lvl1":"PR Analysis & Commit Plan","lvl2":"Total scope","lvl3":""}},
9478
9456
  {"objectID":"021f7ff0ed44464f3674896c96359a76798b23c54494dba0a14256f1317f83a7","title":"Risk level: medium","url":"/docs/provider-integration/12-pr-analysis#risk-level-medium","content":"Touches public SDK API (new providers visible at runtime via the AIProviderName.DEEPSEEK constant or the string id \"deepseek\", etc.)\nModifies shared pricing logic (pricing.ts _default fallback) — could affect other providers\nModifies 12 test suite files (changes shared PROVIDER_MAX_TOKENS map and fallback)\nTest changes are backwards-compatible — same tests pass for existing providers","hierarchy":{"lvl0":"Provider Integration","lvl1":"PR Analysis & Commit Plan","lvl2":"Risk level: medium","lvl3":""}},
9479
- {"objectID":"e5cc48d13e162f6188f0c4c1d83f1b34fafee0844c2a3c6f141c2bd446492c56","title":"A. New provider implementations (4 files, ~1000 LOC)","url":"/docs/provider-integration/12-pr-analysis#a-new-provider-implementations-4-files-1000-loc","content":"All four:\nExtend BaseProvider\nUse createOpenAI(...).chat() for /v1/chat/completions endpoint (NOT /v1/responses)\nWrap streamText with withClientStreamSpan for OTEL tracing (NOT withClientSpan — that ends the span when the callback returns, before the iterable is consumed; for streaming use the *StreamSpan variant that wraps the returned iterable)\nEmit neurolink.provider.stream span with proper gen_ai.* attrs\nUse makeLoggingFetch to capture upstream non-2xx response bodies\nImplement all 5 BaseProvider abstract methods (executeStream, getProviderName, getDefaultModel, getAISDKModel, formatProviderError)","hierarchy":{"lvl0":"Provider Integration","lvl1":"PR Analysis & Commit Plan","lvl2":"A. New provider implementations (4 files, ~1000 LOC)","lvl3":""}},
9457
+ {"objectID":"e5cc48d13e162f6188f0c4c1d83f1b34fafee0844c2a3c6f141c2bd446492c56","title":"A. New provider implementations (4 files, ~1000 LOC)","url":"/docs/provider-integration/12-pr-analysis#a-new-provider-implementations-4-files-1000-loc","content":"All four:\nExtend BaseProvider\nUse createOpenAI(...).chat() for /v1/chat/completions endpoint (NOT /v1/responses)\nWrap streamText with withClientStreamSpan for OTEL tracing (NOT withClientSpan — that ends the span when the callback returns, before the iterable is consumed; for streaming use the *StreamSpan variant that wraps the returned iterable)\nEmit provider.stream span with proper gen_ai.* attrs\nUse makeLoggingFetch to capture upstream non-2xx response bodies\nImplement all 5 BaseProvider abstract methods (executeStream, getProviderName, getDefaultModel, getAISDKModel, formatProviderError)","hierarchy":{"lvl0":"Provider Integration","lvl1":"PR Analysis & Commit Plan","lvl2":"A. New provider implementations (4 files, ~1000 LOC)","lvl3":""}},
9480
9458
  {"objectID":"2d0ba43a71df75d5b582cdeb78dc95a254da373bb04855cf606c1268706b2028","title":"B. Core integration changes (10 modified files)","url":"/docs/provider-integration/12-pr-analysis#b-core-integration-changes-10-modified-files","content":"| File | Change |\n| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| src/lib/factories/providerRegistry.ts | 4 dynamic-import registrations (per CLAUDE.md rule #1) |\n| src/lib/types/providers.ts | NeurolinkCredentials extended + new NvidiaNimExtraBody type |\n| src/lib/constants/enums.ts | AIProviderName enum + 4 model enums |\n| src/lib/constants/contextWindows.ts | 4 sections with model context windows |\n| src/lib/utils/pricing.ts | 4 entries + _default sentinel as provider-level fallback.","hierarchy":{"lvl0":"Provider Integration","lvl1":"PR Analysis & Commit Plan","lvl2":"B. Core integration changes (10 modified files)","lvl3":""}},
9481
9459
  {"objectID":"4fda89121e2641fee9ddcd6b59672fa2a973383a712ae9f95012652baad61d35","title":"C. Test infrastructure fixes (15 modified files)","url":"/docs/provider-integration/12-pr-analysis#c-test-infrastructure-fixes-15-modified-files","content":"The biggest fix — 12 test files had PROVIDER_MAX_TOKENS[provider] || 8192. For our local providers (8K context window), this set maxTokens = contextWindow → availableInputTokens = 0 → every memory/context/mcp test failed instantly with \"Budget: 0 tokens\". The bug existed for any unknown provider (silent broken test).\ntest/continuous-test-suite-context.ts ← Budget=0 fix + Vertex Compaction tests now generic\ntest/continuous-test-suite-evaluation.ts ← Budget=0 fix + dimension-specific RAGAS judge prompts\ntest/continuous-test-suite-evaluation-scoring.ts ← Budget=0 fix\ntest/continuous-test-suite-mcp.ts ← added new providers to map\ntest/continuous-test-suite-mcp-http.ts ← Budget=0 fix\ntest/continuous-test-suite-media-gen.ts ← Budget=0 fix\ntest/continuous-test-suite-memory.ts ← Budget=0 fix\ntest/continuous-test-suite-observability.ts ← Budget=0 fix + TEST_TIMEOUT_MS env var\ntest/continuous-test-suite-ppt.ts ← Budget=0 fix\ntest/continuous-test-suite-providers.ts ← Gemini 3 DisableTools generic, Observability Spans Pipeline-A skip\ntest/continuous-test-suite-session-memory-bugs.ts ← Budget=0 fix\ntest/continuous-test-suite-tts.ts ← Budget=0 fix\ntest/continuous-test-suite-workflow.ts ← Budget=0 fix\ntest/continuous-test-suite-client.ts ← pass timeout: TEST_CONFIG.timeout to createServer\ntest/continuous-test-suite-credentials.ts ← credKeys extended","hierarchy":{"lvl0":"Provider Integration","lvl1":"PR Analysis & Commit Plan","lvl2":"C. Test infrastructure fixes (15 modified files)","lvl3":""}},
9482
9460
  {"objectID":"7583d4e601727d368308fd28eb617e673e56ace60b207c4cab00630c5379dc73","title":"E. Config (3 files)","url":"/docs/provider-integration/12-pr-analysis#e-config-3-files","content":".env.example — 4 provider env-var sections with comments\npackage.json — 4 new test scripts (test:dynamic, test:proxy, test:bugfixes, test:new-providers) + js-yaml dep\npnpm-lock.yaml — 43-line diff for js-yaml + @types/js-yaml","hierarchy":{"lvl0":"Provider Integration","lvl1":"PR Analysis & Commit Plan","lvl2":"E. Config (3 files)","lvl3":""}},
@@ -11113,13 +11091,13 @@
11113
11091
  {"objectID":"8483e8604b827c375e1d484f6f21698c7c22473f0288a5c0db5e77c8588f9c51","title":"Vertex AI","url":"/docs/skills/neurolink-guide/SKILL#vertex-ai","content":"VERTEXPROJECTID=...\nGOOGLEAPPLICATIONCREDENTIALS=/path/to/credentials.json","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Usage Guide","lvl2":"Vertex AI","lvl3":""}},
11114
11092
  {"objectID":"922c91c0569306209b5383b4be7f34a9b396d4bfe3f3580db8c4755fcb0f1820","title":"AWS Bedrock","url":"/docs/skills/neurolink-guide/SKILL#aws-bedrock","content":"AWSACCESSKEY_ID=...\nAWSSECRETACCESS_KEY=...\nAWS_REGION=us-east-1\n`","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Usage Guide","lvl2":"AWS Bedrock","lvl3":""}},
11115
11093
  {"objectID":"184cf0696cfc7d962adf6ad61c0e193eaef3c83cfb995d0f00ca92ce875deb4a","title":"Getting Help","url":"/docs/skills/neurolink-guide/SKILL#getting-help","content":"Check the relevant reference file above\nReview troubleshooting.md for common issues\nLook at code templates in templates/\nRead the full CLAUDE.md in the project root for architecture details\n\nInstructions for Claude: Based on the user's query about $ARGUMENTS, read the appropriate reference file and provide specific guidance. If no topic is specified, give a general overview of NeuroLink capabilities and ask what they'd like help with.","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Usage Guide","lvl2":"Getting Help","lvl3":""}},
11116
- {"objectID":"9b5e5af2fde4b6f4fef52d088cdbe8b59f5ad3ee10515d5df80e9f4ee8001d35","title":"NeuroLink Advanced Features","url":"/docs/skills/neurolink-guide/advanced-features","content":"NeuroLink Advanced Features\n\nEnterprise-grade capabilities for production AI applications.\n\nHuman-in-the-Loop (HITL)\n\nRequire approval for sensitive tool operations.\n\nConfiguration\n\nCustom Rules\n\nHandling Confirmations\n\nWorkflow Engine\n\nCreate complex AI workflows with branching and parallel execution.\n\nBasic Workflow\n\nFluent Builder API\n\nWorkflow with Checkpointing\n\nEnsemble Workflow\n\nRun multiple models and synthesize results:\n\nExtended Thinking\n\nEnable deep reasoning for complex tasks.\n\nAnthropic (Claude)\n\nGoogle (Gemini 3)\n\nObservability\n\nLangfuse Integration\n\nContext Management\n\nExternal TracerProvider\n\nFor apps with existing OpenTelemetry setup:\n\nCustom Spans\n\nServer Adapters\n\nDeploy NeuroLink as an HTTP API.\n\nHono (Default)\n\nExpress\n\nFastify\n\nAvailable Routes\n\n| Route | Method | Description |\n| ---------------- | ------ | -------------------- |\n| /api/generate | POST | Text generation |\n| /api/stream | POST | Streaming generation |\n| /api/tools | GET | List available tools |\n| /api/providers | GET | Provider status |\n| /api/health | GET | Health check |\n\nMulti-Agent Networks\n\nOrchestrate multiple specialized agents.\n\nDefine Agents\n\nCreate Network\n\nRouting Agent\n\nEvaluation and Scoring\n\nScore AI responses for quality.\n\nBuilt-in Scorers\n\nAvailable Scorers\n\n| Scorer | Type | Description |\n| --------------- | ---- | ---------------------------- |\n| relevance | LLM | Response relevance to prompt |\n| coherence | LLM | Logical flow and structure |\n| completeness | LLM | Coverage of topic |\n| accuracy | LLM | Factual correctness |\n| toxicity | Rule | Detect harmful content |\n| length | Rule | Response length check |\n| json-validity | Rule | Valid JSON output |\n| regex-match | Rule | Pattern matching |\n\nCustom Evaluation\n\nStorage Abstraction\n\nUnified storage layer for persistence.\n\nAuthentication\n\nProtect your NeuroLink API.\n\nSupported Auth Types\nJWT tokens\nAPI keys\nOAuth2\nSession-based\nCustom middleware\n\nDeployment\n\nDocker\n\nAWS Lambda\n\nVercel\n\nNext Steps\nSDK quickstart - Basic usage\nProviders - Provider configuration\nTools - MCP integration\nTroubleshooting - Common issues","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"","lvl3":""}},
11094
+ {"objectID":"9b5e5af2fde4b6f4fef52d088cdbe8b59f5ad3ee10515d5df80e9f4ee8001d35","title":"NeuroLink Advanced Features","url":"/docs/skills/neurolink-guide/advanced-features","content":"NeuroLink Advanced Features\n\nEnterprise-grade capabilities for production AI applications.\n\nHuman-in-the-Loop (HITL)\n\nRequire approval for sensitive tool operations.\n\nConfiguration\n\nCustom Rules\n\nHandling Confirmations\n\nWorkflow Engine\n\nCreate complex AI workflows with branching and parallel execution.\n\nBasic Workflow\n\nFluent Builder API\n\nWorkflow with Checkpointing\n\nEnsemble Workflow\n\nRun multiple models and synthesize results:\n\nExtended Thinking\n\nEnable deep reasoning for complex tasks.\n\nAnthropic (Claude)\n\nGoogle (Gemini 3)\n\nObservability\n\nLangfuse Integration\n\nContext Management\n\nExternal TracerProvider\n\nIf your app registers its own OpenTelemetry provider, NeuroLink detects it and creates no provider. Recommended: add createExporterSpanProcessor() and pass the Langfuse keys to new NeuroLink({ observability: { langfuse } }). Alternatively add new LangfuseSpanProcessor() with its own keys (NeuroLink's mask, chunking and retry do not apply to it) and defaults; no custom shouldExportSpan is needed, because every observation span NeuroLink emits carries gen_ai.observation.type, which the default filter exports, while infrastructure spans are not exported:\n\nCustom Spans\n\nServer Adapters\n\nDeploy NeuroLink as an HTTP API.\n\nHono (Default)\n\nExpress\n\nFastify\n\nAvailable Routes\n\n| Route | Method | Description |\n| ---------------- | ------ | -------------------- |\n| /api/generate | POST | Text generation |\n| /api/stream | POST | Streaming generation |\n| /api/tools | GET | List available tools |\n| /api/providers | GET | Provider status |\n| /api/health | GET | Health check |\n\nMulti-Agent Networks\n\nOrchestrate multiple specialized agents.\n\nDefine Agents\n\nCreate Network\n\nRouting Agent\n\nEvaluation and Scoring\n\nScore AI responses for quality.\n\nBuilt-in Scorers\n\nAvailable Scorers\n\n| Scorer | Type | Description |\n| --------------- | ---- | ---------------------------- |\n| relevance | LLM | Response relevance to prompt |\n| coherence | LLM | Logical flow and structure |\n| completeness | LLM | Coverage of topic |\n| accuracy | LLM | Factual correctness |\n| toxicity | Rule | Detect harmful content |\n| length | Rule | Response length check |\n| json-validity | Rule | Valid JSON output |\n| regex-match | Rule | Pattern matching |\n\nCustom Evaluation\n\nStorage Abstraction\n\nUnified storage layer for persistence.\n\nAuthentication\n\nProtect your NeuroLink API.\n\nSupported Auth Types\nJWT tokens\nAPI keys\nOAuth2\nSession-based\nCustom middleware\n\nDeployment\n\nDocker\n\nAWS Lambda\n\nVercel\n\nNext Steps\nSDK quickstart - Basic usage\nProviders - Provider configuration\nTools - MCP integration\nTroubleshooting - Common issues","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"","lvl3":""}},
11117
11095
  {"objectID":"290ca0d5b310e10233c313f7972063dddb547b3c692550ce9d1522cb3eab5ef2","title":"NeuroLink Advanced Features","url":"/docs/skills/neurolink-guide/advanced-features#neurolink-advanced-features","content":"Enterprise-grade capabilities for production AI applications.","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"NeuroLink Advanced Features","lvl3":""}},
11118
11096
  {"objectID":"7800cad78bd1ed6628289255e48b3e1deb0afc0d9bd3a121a7a1320bac962ff1","title":"Human-in-the-Loop (HITL)","url":"/docs/skills/neurolink-guide/advanced-features#human-in-the-loop-hitl","content":"Require approval for sensitive tool operations.","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"Human-in-the-Loop (HITL)","lvl3":""}},
11119
11097
  {"objectID":"93f327bf174812abb315ef0d1ba8c6605ec6d2e7e58ce321162b2a415b01a09f","title":"Workflow Engine","url":"/docs/skills/neurolink-guide/advanced-features#workflow-engine","content":"Create complex AI workflows with branching and parallel execution.","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"Workflow Engine","lvl3":""}},
11120
11098
  {"objectID":"fd22282d8c0ae49ad14bd39937ddd9cf1e4e25d609ae8d92e3cc11131855a73d","title":"Ensemble Workflow","url":"/docs/skills/neurolink-guide/advanced-features#ensemble-workflow","content":"Run multiple models and synthesize results:","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"Ensemble Workflow","lvl3":""}},
11121
11099
  {"objectID":"69f6fbbe2cedd608330016256cebae6b6c28da61b0d35a5e83c603aeadb12e6d","title":"Extended Thinking","url":"/docs/skills/neurolink-guide/advanced-features#extended-thinking","content":"Enable deep reasoning for complex tasks.","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"Extended Thinking","lvl3":""}},
11122
- {"objectID":"442da0b12136bb5fb7bd1be88b503df08b6a84264b6d21bcd94c25e8527a2318","title":"External TracerProvider","url":"/docs/skills/neurolink-guide/advanced-features#external-tracerprovider","content":"For apps with existing OpenTelemetry setup:","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"External TracerProvider","lvl3":""}},
11100
+ {"objectID":"442da0b12136bb5fb7bd1be88b503df08b6a84264b6d21bcd94c25e8527a2318","title":"External TracerProvider","url":"/docs/skills/neurolink-guide/advanced-features#external-tracerprovider","content":"If your app registers its own OpenTelemetry provider, NeuroLink detects it and creates no provider. Recommended: add createExporterSpanProcessor() and pass the Langfuse keys to new NeuroLink({ observability: { langfuse } }). Alternatively add new LangfuseSpanProcessor() with its own keys (NeuroLink's mask, chunking and retry do not apply to it) and defaults; no custom shouldExportSpan is needed, because every observation span NeuroLink emits carries gen_ai.observation.type, which the default filter exports, while infrastructure spans are not exported:","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"External TracerProvider","lvl3":""}},
11123
11101
  {"objectID":"dac3babc0236c129d995e34a14f533453c13f07395ef397270be07439690bb80","title":"Server Adapters","url":"/docs/skills/neurolink-guide/advanced-features#server-adapters","content":"Deploy NeuroLink as an HTTP API.","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"Server Adapters","lvl3":""}},
11124
11102
  {"objectID":"c634dd539307ce0c33ab657a4b9e6d70b07f79a88d6245042261eb969a51abea","title":"Available Routes","url":"/docs/skills/neurolink-guide/advanced-features#available-routes","content":"| Route | Method | Description |\n| ---------------- | ------ | -------------------- |\n| /api/generate | POST | Text generation |\n| /api/stream | POST | Streaming generation |\n| /api/tools | GET | List available tools |\n| /api/providers | GET | Provider status |\n| /api/health | GET | Health check |","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"Available Routes","lvl3":""}},
11125
11103
  {"objectID":"1fd9814b1ef8a1bcbfbbabe5cddf4e051928ba0c8eb6faabf9905f25bcd04ea8","title":"Multi-Agent Networks","url":"/docs/skills/neurolink-guide/advanced-features#multi-agent-networks","content":"Orchestrate multiple specialized agents.","hierarchy":{"lvl0":"Skills","lvl1":"NeuroLink Advanced Features","lvl2":"Multi-Agent Networks","lvl3":""}},