@juspay/neurolink 9.15.0 → 9.17.0

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 (196) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +22 -20
  3. package/dist/adapters/video/videoAnalyzer.d.ts +1 -1
  4. package/dist/adapters/video/videoAnalyzer.js +10 -8
  5. package/dist/cli/commands/setup-anthropic.js +1 -14
  6. package/dist/cli/commands/setup-azure.js +1 -12
  7. package/dist/cli/commands/setup-bedrock.js +1 -9
  8. package/dist/cli/commands/setup-google-ai.js +1 -12
  9. package/dist/cli/commands/setup-openai.js +1 -14
  10. package/dist/cli/commands/workflow.d.ts +27 -0
  11. package/dist/cli/commands/workflow.js +216 -0
  12. package/dist/cli/factories/commandFactory.js +79 -20
  13. package/dist/cli/index.js +0 -1
  14. package/dist/cli/parser.js +4 -1
  15. package/dist/cli/utils/maskCredential.d.ts +11 -0
  16. package/dist/cli/utils/maskCredential.js +23 -0
  17. package/dist/constants/contextWindows.js +107 -16
  18. package/dist/constants/enums.d.ts +99 -15
  19. package/dist/constants/enums.js +152 -22
  20. package/dist/context/budgetChecker.js +1 -1
  21. package/dist/context/contextCompactor.js +31 -4
  22. package/dist/context/emergencyTruncation.d.ts +21 -0
  23. package/dist/context/emergencyTruncation.js +88 -0
  24. package/dist/context/errorDetection.d.ts +16 -0
  25. package/dist/context/errorDetection.js +48 -1
  26. package/dist/context/errors.d.ts +19 -0
  27. package/dist/context/errors.js +21 -0
  28. package/dist/context/stages/slidingWindowTruncator.d.ts +6 -0
  29. package/dist/context/stages/slidingWindowTruncator.js +159 -24
  30. package/dist/context/stages/structuredSummarizer.js +2 -2
  31. package/dist/core/baseProvider.js +306 -200
  32. package/dist/core/conversationMemoryManager.js +104 -61
  33. package/dist/core/evaluationProviders.js +16 -33
  34. package/dist/core/factory.js +237 -164
  35. package/dist/core/modules/GenerationHandler.js +175 -116
  36. package/dist/core/modules/MessageBuilder.js +222 -170
  37. package/dist/core/modules/StreamHandler.d.ts +1 -0
  38. package/dist/core/modules/StreamHandler.js +95 -27
  39. package/dist/core/modules/TelemetryHandler.d.ts +10 -1
  40. package/dist/core/modules/TelemetryHandler.js +25 -7
  41. package/dist/core/modules/ToolsManager.js +115 -191
  42. package/dist/core/redisConversationMemoryManager.js +418 -282
  43. package/dist/factories/providerRegistry.d.ts +5 -0
  44. package/dist/factories/providerRegistry.js +20 -2
  45. package/dist/index.d.ts +2 -2
  46. package/dist/index.js +4 -2
  47. package/dist/lib/adapters/video/videoAnalyzer.d.ts +1 -1
  48. package/dist/lib/adapters/video/videoAnalyzer.js +10 -8
  49. package/dist/lib/constants/contextWindows.js +107 -16
  50. package/dist/lib/constants/enums.d.ts +99 -15
  51. package/dist/lib/constants/enums.js +152 -22
  52. package/dist/lib/context/budgetChecker.js +1 -1
  53. package/dist/lib/context/contextCompactor.js +31 -4
  54. package/dist/lib/context/emergencyTruncation.d.ts +21 -0
  55. package/dist/lib/context/emergencyTruncation.js +89 -0
  56. package/dist/lib/context/errorDetection.d.ts +16 -0
  57. package/dist/lib/context/errorDetection.js +48 -1
  58. package/dist/lib/context/errors.d.ts +19 -0
  59. package/dist/lib/context/errors.js +22 -0
  60. package/dist/lib/context/stages/slidingWindowTruncator.d.ts +6 -0
  61. package/dist/lib/context/stages/slidingWindowTruncator.js +159 -24
  62. package/dist/lib/context/stages/structuredSummarizer.js +2 -2
  63. package/dist/lib/core/baseProvider.js +306 -200
  64. package/dist/lib/core/conversationMemoryManager.js +104 -61
  65. package/dist/lib/core/evaluationProviders.js +16 -33
  66. package/dist/lib/core/factory.js +237 -164
  67. package/dist/lib/core/modules/GenerationHandler.js +175 -116
  68. package/dist/lib/core/modules/MessageBuilder.js +222 -170
  69. package/dist/lib/core/modules/StreamHandler.d.ts +1 -0
  70. package/dist/lib/core/modules/StreamHandler.js +95 -27
  71. package/dist/lib/core/modules/TelemetryHandler.d.ts +10 -1
  72. package/dist/lib/core/modules/TelemetryHandler.js +25 -7
  73. package/dist/lib/core/modules/ToolsManager.js +115 -191
  74. package/dist/lib/core/redisConversationMemoryManager.js +418 -282
  75. package/dist/lib/factories/providerRegistry.d.ts +5 -0
  76. package/dist/lib/factories/providerRegistry.js +20 -2
  77. package/dist/lib/index.d.ts +2 -2
  78. package/dist/lib/index.js +4 -2
  79. package/dist/lib/mcp/externalServerManager.js +66 -0
  80. package/dist/lib/mcp/mcpCircuitBreaker.js +24 -0
  81. package/dist/lib/mcp/mcpClientFactory.js +16 -0
  82. package/dist/lib/mcp/toolDiscoveryService.js +32 -6
  83. package/dist/lib/mcp/toolRegistry.js +193 -123
  84. package/dist/lib/neurolink.d.ts +6 -0
  85. package/dist/lib/neurolink.js +1162 -646
  86. package/dist/lib/providers/amazonBedrock.d.ts +1 -1
  87. package/dist/lib/providers/amazonBedrock.js +521 -319
  88. package/dist/lib/providers/anthropic.js +73 -17
  89. package/dist/lib/providers/anthropicBaseProvider.js +77 -17
  90. package/dist/lib/providers/googleAiStudio.d.ts +1 -1
  91. package/dist/lib/providers/googleAiStudio.js +292 -227
  92. package/dist/lib/providers/googleVertex.d.ts +36 -1
  93. package/dist/lib/providers/googleVertex.js +553 -260
  94. package/dist/lib/providers/ollama.js +329 -278
  95. package/dist/lib/providers/openAI.js +77 -19
  96. package/dist/lib/providers/sagemaker/parsers.js +3 -3
  97. package/dist/lib/providers/sagemaker/streaming.js +3 -3
  98. package/dist/lib/proxy/proxyFetch.js +81 -48
  99. package/dist/lib/rag/ChunkerFactory.js +1 -1
  100. package/dist/lib/rag/chunkers/MarkdownChunker.d.ts +22 -0
  101. package/dist/lib/rag/chunkers/MarkdownChunker.js +213 -9
  102. package/dist/lib/rag/chunking/markdownChunker.d.ts +16 -0
  103. package/dist/lib/rag/chunking/markdownChunker.js +174 -2
  104. package/dist/lib/rag/pipeline/contextAssembly.js +2 -1
  105. package/dist/lib/rag/ragIntegration.d.ts +18 -1
  106. package/dist/lib/rag/ragIntegration.js +94 -14
  107. package/dist/lib/rag/retrieval/vectorQueryTool.js +21 -4
  108. package/dist/lib/server/abstract/baseServerAdapter.js +4 -1
  109. package/dist/lib/server/adapters/fastifyAdapter.js +35 -30
  110. package/dist/lib/services/server/ai/observability/instrumentation.d.ts +32 -0
  111. package/dist/lib/services/server/ai/observability/instrumentation.js +39 -0
  112. package/dist/lib/telemetry/attributes.d.ts +52 -0
  113. package/dist/lib/telemetry/attributes.js +61 -0
  114. package/dist/lib/telemetry/index.d.ts +3 -0
  115. package/dist/lib/telemetry/index.js +3 -0
  116. package/dist/lib/telemetry/telemetryService.d.ts +6 -0
  117. package/dist/lib/telemetry/telemetryService.js +6 -0
  118. package/dist/lib/telemetry/tracers.d.ts +15 -0
  119. package/dist/lib/telemetry/tracers.js +17 -0
  120. package/dist/lib/telemetry/withSpan.d.ts +9 -0
  121. package/dist/lib/telemetry/withSpan.js +35 -0
  122. package/dist/lib/types/contextTypes.d.ts +10 -0
  123. package/dist/lib/types/streamTypes.d.ts +14 -0
  124. package/dist/lib/utils/conversationMemory.js +123 -84
  125. package/dist/lib/utils/logger.d.ts +5 -0
  126. package/dist/lib/utils/logger.js +50 -2
  127. package/dist/lib/utils/messageBuilder.js +22 -42
  128. package/dist/lib/utils/modelDetection.js +3 -3
  129. package/dist/lib/utils/providerRetry.d.ts +41 -0
  130. package/dist/lib/utils/providerRetry.js +114 -0
  131. package/dist/lib/utils/retryability.d.ts +14 -0
  132. package/dist/lib/utils/retryability.js +23 -0
  133. package/dist/lib/utils/sanitizers/svg.js +4 -5
  134. package/dist/lib/utils/tokenEstimation.d.ts +11 -1
  135. package/dist/lib/utils/tokenEstimation.js +19 -4
  136. package/dist/lib/utils/videoAnalysisProcessor.js +7 -3
  137. package/dist/mcp/externalServerManager.js +66 -0
  138. package/dist/mcp/mcpCircuitBreaker.js +24 -0
  139. package/dist/mcp/mcpClientFactory.js +16 -0
  140. package/dist/mcp/toolDiscoveryService.js +32 -6
  141. package/dist/mcp/toolRegistry.js +193 -123
  142. package/dist/neurolink.d.ts +6 -0
  143. package/dist/neurolink.js +1162 -646
  144. package/dist/providers/amazonBedrock.d.ts +1 -1
  145. package/dist/providers/amazonBedrock.js +521 -319
  146. package/dist/providers/anthropic.js +73 -17
  147. package/dist/providers/anthropicBaseProvider.js +77 -17
  148. package/dist/providers/googleAiStudio.d.ts +1 -1
  149. package/dist/providers/googleAiStudio.js +292 -227
  150. package/dist/providers/googleVertex.d.ts +36 -1
  151. package/dist/providers/googleVertex.js +553 -260
  152. package/dist/providers/ollama.js +329 -278
  153. package/dist/providers/openAI.js +77 -19
  154. package/dist/providers/sagemaker/parsers.js +3 -3
  155. package/dist/providers/sagemaker/streaming.js +3 -3
  156. package/dist/proxy/proxyFetch.js +81 -48
  157. package/dist/rag/ChunkerFactory.js +1 -1
  158. package/dist/rag/chunkers/MarkdownChunker.d.ts +22 -0
  159. package/dist/rag/chunkers/MarkdownChunker.js +213 -9
  160. package/dist/rag/chunking/markdownChunker.d.ts +16 -0
  161. package/dist/rag/chunking/markdownChunker.js +174 -2
  162. package/dist/rag/pipeline/contextAssembly.js +2 -1
  163. package/dist/rag/ragIntegration.d.ts +18 -1
  164. package/dist/rag/ragIntegration.js +94 -14
  165. package/dist/rag/retrieval/vectorQueryTool.js +21 -4
  166. package/dist/server/abstract/baseServerAdapter.js +4 -1
  167. package/dist/server/adapters/fastifyAdapter.js +35 -30
  168. package/dist/services/server/ai/observability/instrumentation.d.ts +32 -0
  169. package/dist/services/server/ai/observability/instrumentation.js +39 -0
  170. package/dist/telemetry/attributes.d.ts +52 -0
  171. package/dist/telemetry/attributes.js +60 -0
  172. package/dist/telemetry/index.d.ts +3 -0
  173. package/dist/telemetry/index.js +3 -0
  174. package/dist/telemetry/telemetryService.d.ts +6 -0
  175. package/dist/telemetry/telemetryService.js +6 -0
  176. package/dist/telemetry/tracers.d.ts +15 -0
  177. package/dist/telemetry/tracers.js +16 -0
  178. package/dist/telemetry/withSpan.d.ts +9 -0
  179. package/dist/telemetry/withSpan.js +34 -0
  180. package/dist/types/contextTypes.d.ts +10 -0
  181. package/dist/types/streamTypes.d.ts +14 -0
  182. package/dist/utils/conversationMemory.js +123 -84
  183. package/dist/utils/logger.d.ts +5 -0
  184. package/dist/utils/logger.js +50 -2
  185. package/dist/utils/messageBuilder.js +22 -42
  186. package/dist/utils/modelDetection.js +3 -3
  187. package/dist/utils/providerRetry.d.ts +41 -0
  188. package/dist/utils/providerRetry.js +113 -0
  189. package/dist/utils/retryability.d.ts +14 -0
  190. package/dist/utils/retryability.js +22 -0
  191. package/dist/utils/sanitizers/svg.js +4 -5
  192. package/dist/utils/tokenEstimation.d.ts +11 -1
  193. package/dist/utils/tokenEstimation.js +19 -4
  194. package/dist/utils/videoAnalysisProcessor.js +7 -3
  195. package/dist/workflow/config.d.ts +26 -26
  196. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [9.17.0](https://github.com/juspay/neurolink/compare/v9.16.0...v9.17.0) (2026-03-06)
2
+
3
+ ### Features
4
+
5
+ - **(landing):** nervous-system landing page redesign, docs overhaul, and SDK fixes ([fe756b3](https://github.com/juspay/neurolink/commit/fe756b393c0376f6c37fbab6c59ec2b31330a59f))
6
+
7
+ ## [9.16.0](https://github.com/juspay/neurolink/compare/v9.15.0...v9.16.0) (2026-03-02)
8
+
9
+ ### Features
10
+
11
+ - **(sdk):** add models, observability, RAG enhancements, landing overhaul, and 45 review fixes ([eb79a1f](https://github.com/juspay/neurolink/commit/eb79a1f51dfd789da49130b6a05fa40ed38fd668))
12
+
1
13
  ## [9.15.0](https://github.com/juspay/neurolink/compare/v9.14.0...v9.15.0) (2026-03-01)
2
14
 
3
15
  ### Features
package/README.md CHANGED
@@ -1,23 +1,25 @@
1
- <div align="center">
2
- <h1>🧠 NeuroLink</h1>
3
- <p><strong>The Enterprise AI SDK for Production Applications</strong></p>
4
- <p>13 Providers | 58+ MCP Tools | HITL Security | Redis Persistence</p>
5
- </div>
6
-
7
- <div align="center">
8
-
9
- [![npm version](https://badge.fury.io/js/%40juspay%2Fneurolink.svg)](https://www.npmjs.com/package/@juspay/neurolink)
10
- [![npm downloads](https://img.shields.io/npm/dw/@juspay/neurolink)](https://www.npmjs.com/package/@juspay/neurolink)
11
- [![Build Status](https://github.com/juspay/neurolink/actions/workflows/ci.yml/badge.svg)](https://github.com/juspay/neurolink/actions/workflows/ci.yml)
12
- [![Coverage Status](https://coveralls.io/repos/github/juspay/neurolink/badge.svg?branch=main)](https://coveralls.io/github/juspay/neurolink?branch=main)
13
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
14
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
15
- [![GitHub Stars](https://img.shields.io/github/stars/juspay/neurolink)](https://github.com/juspay/neurolink/stargazers)
16
- [![Discord](https://img.shields.io/discord/DISCORD_SERVER_ID?label=Discord&logo=discord)](https://discord.gg/neurolink)
17
-
18
- </div>
19
-
20
- Enterprise AI development platform with unified provider access, production-ready tooling, and an opinionated factory architecture. NeuroLink ships as both a TypeScript SDK and a professional CLI so teams can build, operate, and iterate on AI features quickly.
1
+ # NeuroLink
2
+
3
+ **The pipe layer for the AI nervous system.**
4
+
5
+ AI intelligence flows as streams — tokens, tool calls, memory, voice, documents.
6
+ NeuroLink is the vascular layer that carries these streams from where they are
7
+ generated (LLM providers: the neurons) to where they are needed (connectors: the organs).
8
+
9
+ ```typescript
10
+ import { NeuroLink } from "@juspay/neurolink";
11
+
12
+ const pipe = new NeuroLink({ defaultProvider: "anthropic" });
13
+
14
+ // Everything is a stream
15
+ for await (const token of pipe.stream({ prompt: "Hello" })) {
16
+ process.stdout.write(token);
17
+ }
18
+ ```
19
+
20
+ **[→ Docs](https://docs.neurolink.ink) Ā· [→ Quick Start](https://docs.neurolink.ink/docs/getting-started/quick-start) Ā· [→ npm](https://www.npmjs.com/package/@juspay/neurolink)**
21
+
22
+ ---
21
23
 
22
24
  ## 🧠 What is NeuroLink?
23
25
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Video Analysis Handler
3
3
  *
4
- * Provides video analysis using Google's Gemini 2.0 Flash model.
4
+ * Provides video analysis using Google's Gemini 2.5 Flash model.
5
5
  * Supports both Vertex AI and Gemini API providers.
6
6
  *
7
7
  * @module adapters/video/geminiVideoAnalyzer
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Video Analysis Handler
3
3
  *
4
- * Provides video analysis using Google's Gemini 2.0 Flash model.
4
+ * Provides video analysis using Google's Gemini 2.5 Flash model.
5
5
  * Supports both Vertex AI and Gemini API providers.
6
6
  *
7
7
  * @module adapters/video/geminiVideoAnalyzer
@@ -13,7 +13,7 @@ import { NeuroLinkError, ErrorFactory } from "../../utils/errorHandling.js";
13
13
  // ---------------------------------------------------------------------------
14
14
  // Shared config
15
15
  // ---------------------------------------------------------------------------
16
- const DEFAULT_MODEL = "gemini-2.0-flash";
16
+ const DEFAULT_MODEL = "gemini-2.5-flash";
17
17
  const DEFAULT_LOCATION = "us-central1";
18
18
  /**
19
19
  * Extract content items from user messages
@@ -223,14 +223,16 @@ async function getVertexConfig() {
223
223
  }
224
224
  export async function analyzeVideo(messages, options = {}) {
225
225
  const provider = options.provider || AIProviderName.AUTO;
226
- // Vertex — only when GOOGLE_VERTEX_PROJECT is explicitly set
227
- if (provider === AIProviderName.VERTEX || provider === AIProviderName.AUTO) {
226
+ // Vertex — only when Vertex credentials are configured
227
+ if (provider === AIProviderName.VERTEX ||
228
+ (provider === AIProviderName.AUTO &&
229
+ (process.env.GOOGLE_VERTEX_PROJECT || process.env.GOOGLE_CLOUD_PROJECT))) {
228
230
  return analyzeVideoWithVertexAI(messages, options);
229
231
  }
230
- // Gemini API — when GOOGLE_AI_API_KEY is set
231
- if (provider === AIProviderName.GOOGLE_AI && process.env.GOOGLE_AI_API_KEY) {
232
+ // Gemini API — when Google AI API key is available
233
+ if (provider === AIProviderName.GOOGLE_AI ||
234
+ (provider === AIProviderName.AUTO && process.env.GOOGLE_AI_API_KEY)) {
232
235
  return analyzeVideoWithGeminiAPI(messages, options);
233
236
  }
234
- throw new Error("No valid provider configuration found. " +
235
- "Set GOOGLE_VERTEX_PROJECT for Vertex AI or GOOGLE_AI_API_KEY for Gemini API.");
237
+ throw ErrorFactory.invalidConfiguration("video analysis provider", "No valid provider configuration found. Set GOOGLE_VERTEX_PROJECT for Vertex AI or GOOGLE_AI_API_KEY for Gemini API.");
236
238
  }
@@ -16,6 +16,7 @@ import ora from "ora";
16
16
  import { logger } from "../../lib/utils/logger.js";
17
17
  import { getTopModelChoices } from "../../lib/utils/modelChoices.js";
18
18
  import { AIProviderName } from "../../lib/types/index.js";
19
+ import { maskCredential } from "../utils/maskCredential.js";
19
20
  export async function handleAnthropicSetup(argv) {
20
21
  try {
21
22
  const options = {
@@ -365,20 +366,6 @@ async function updateEnvFile(config) {
365
366
  throw error;
366
367
  }
367
368
  }
368
- /**
369
- * Mask API key for display
370
- */
371
- function maskCredential(credential) {
372
- if (!credential || credential.length < 8) {
373
- return "****";
374
- }
375
- const knownPrefixes = ["sk-ant-"];
376
- const prefix = knownPrefixes.find((p) => credential.startsWith(p)) ??
377
- credential.slice(0, 3);
378
- const end = credential.slice(-4);
379
- const stars = "*".repeat(Math.max(4, credential.length - prefix.length - 4));
380
- return `${prefix}${stars}${end}`;
381
- }
382
369
  /**
383
370
  * Show usage example
384
371
  */
@@ -16,6 +16,7 @@ import { logger } from "../../lib/utils/logger.js";
16
16
  import { updateEnvFile as updateEnvFileShared, displayEnvUpdateSummary, } from "../utils/envManager.js";
17
17
  import { getTopModelChoices } from "../../lib/utils/modelChoices.js";
18
18
  import { AIProviderName } from "../../lib/types/index.js";
19
+ import { maskCredential } from "../utils/maskCredential.js";
19
20
  export async function handleAzureSetup(argv) {
20
21
  try {
21
22
  const options = {
@@ -372,18 +373,6 @@ async function updateEnvFileWithConfig(config) {
372
373
  throw error;
373
374
  }
374
375
  }
375
- /**
376
- * Mask API key for display
377
- */
378
- function maskCredential(credential) {
379
- if (!credential || credential.length < 8) {
380
- return "****";
381
- }
382
- const start = credential.slice(0, 4);
383
- const end = credential.slice(-4);
384
- const middle = "*".repeat(Math.max(4, credential.length - 8));
385
- return `${start}${middle}${end}`;
386
- }
387
376
  /**
388
377
  * Show usage example
389
378
  */
@@ -15,6 +15,7 @@ import { logger } from "../../lib/utils/logger.js";
15
15
  import { updateEnvFile as envUpdate } from "../utils/envManager.js";
16
16
  import { getTopModelChoices } from "../../lib/utils/modelChoices.js";
17
17
  import { AIProviderName } from "../../lib/types/index.js";
18
+ import { maskCredential } from "../utils/maskCredential.js";
18
19
  export async function handleBedrockSetup(argv) {
19
20
  try {
20
21
  const options = {
@@ -453,13 +454,4 @@ function displayUsageExample() {
453
454
  logger.always(chalk.green("šŸš€ You can now use AWS Bedrock with the NeuroLink CLI:"));
454
455
  logger.always(chalk.cyan(" pnpm cli generate 'Hello from Bedrock!' --provider bedrock"));
455
456
  }
456
- function maskCredential(credential) {
457
- if (!credential || credential.length < 8) {
458
- return "****";
459
- }
460
- const start = credential.slice(0, 4);
461
- const end = credential.slice(-4);
462
- const middle = "*".repeat(Math.max(4, credential.length - 8));
463
- return `${start}${middle}${end}`;
464
- }
465
457
  //# sourceMappingURL=setup-bedrock.js.map
@@ -17,6 +17,7 @@ import { GoogleAIModels } from "../../lib/constants/enums.js";
17
17
  import { updateEnvFile as updateEnvFileManager, displayEnvUpdateSummary, } from "../utils/envManager.js";
18
18
  import { getTopModelChoices } from "../../lib/utils/modelChoices.js";
19
19
  import { AIProviderName } from "../../lib/types/index.js";
20
+ import { maskCredential } from "../utils/maskCredential.js";
20
21
  /**
21
22
  * Get the runtime default model that matches the provider implementation
22
23
  */
@@ -326,18 +327,6 @@ async function updateEnvFile(config) {
326
327
  throw error;
327
328
  }
328
329
  }
329
- /**
330
- * Mask API key for display
331
- */
332
- function maskCredential(credential) {
333
- if (!credential || credential.length < 8) {
334
- return "****";
335
- }
336
- const start = credential.slice(0, 7); // Show 'AIza' plus a few chars
337
- const end = credential.slice(-4);
338
- const middle = "*".repeat(Math.max(4, credential.length - 11));
339
- return `${start}${middle}${end}`;
340
- }
341
330
  /**
342
331
  * Show usage example
343
332
  */
@@ -16,6 +16,7 @@ import ora from "ora";
16
16
  import { logger } from "../../lib/utils/logger.js";
17
17
  import { getTopModelChoices } from "../../lib/utils/modelChoices.js";
18
18
  import { AIProviderName } from "../../lib/types/index.js";
19
+ import { maskCredential } from "../utils/maskCredential.js";
19
20
  export async function handleOpenAISetup(argv) {
20
21
  try {
21
22
  const options = {
@@ -358,20 +359,6 @@ async function updateEnvFile(config) {
358
359
  throw error;
359
360
  }
360
361
  }
361
- /**
362
- * Mask API key for display
363
- */
364
- function maskCredential(credential) {
365
- if (!credential || credential.length < 8) {
366
- return "****";
367
- }
368
- const knownPrefixes = ["sk-"];
369
- const prefix = knownPrefixes.find((p) => credential.startsWith(p)) ??
370
- credential.slice(0, 3);
371
- const end = credential.slice(-4);
372
- const stars = "*".repeat(Math.max(4, credential.length - prefix.length - 4));
373
- return `${prefix}${stars}${end}`;
374
- }
375
362
  /**
376
363
  * Show usage example
377
364
  */
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Workflow CLI Commands for NeuroLink
3
+ *
4
+ * Implements commands for workflow management and execution:
5
+ * - neurolink workflow list - List available predefined workflows
6
+ * - neurolink workflow info <name> - Show details of a workflow
7
+ * - neurolink workflow execute <name> <prompt> - Execute a workflow
8
+ */
9
+ import type { CommandModule } from "yargs";
10
+ /**
11
+ * Workflow CLI command factory
12
+ */
13
+ export declare class WorkflowCommandFactory {
14
+ static createWorkflowCommands(): CommandModule;
15
+ /**
16
+ * List all predefined workflows
17
+ */
18
+ private static executeList;
19
+ /**
20
+ * Show details of a specific workflow
21
+ */
22
+ private static executeInfo;
23
+ /**
24
+ * Execute a workflow
25
+ */
26
+ private static executeWorkflow;
27
+ }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Workflow CLI Commands for NeuroLink
3
+ *
4
+ * Implements commands for workflow management and execution:
5
+ * - neurolink workflow list - List available predefined workflows
6
+ * - neurolink workflow info <name> - Show details of a workflow
7
+ * - neurolink workflow execute <name> <prompt> - Execute a workflow
8
+ */
9
+ import chalk from "chalk";
10
+ import ora from "ora";
11
+ /**
12
+ * All predefined workflow configs keyed by their id.
13
+ * Loaded lazily via dynamic import to avoid circular deps.
14
+ */
15
+ async function loadPredefinedWorkflows() {
16
+ const [consensus, fallback, adaptive, multiJudge] = await Promise.all([
17
+ import("../../lib/workflow/workflows/consensusWorkflow.js"),
18
+ import("../../lib/workflow/workflows/fallbackWorkflow.js"),
19
+ import("../../lib/workflow/workflows/adaptiveWorkflow.js"),
20
+ import("../../lib/workflow/workflows/multiJudgeWorkflow.js"),
21
+ ]);
22
+ const configs = [
23
+ consensus.CONSENSUS_3_WORKFLOW,
24
+ consensus.CONSENSUS_3_FAST_WORKFLOW,
25
+ fallback.FAST_FALLBACK_WORKFLOW,
26
+ fallback.AGGRESSIVE_FALLBACK_WORKFLOW,
27
+ adaptive.QUALITY_MAX_WORKFLOW,
28
+ adaptive.SPEED_FIRST_WORKFLOW,
29
+ adaptive.BALANCED_ADAPTIVE_WORKFLOW,
30
+ multiJudge.MULTI_JUDGE_5_WORKFLOW,
31
+ multiJudge.MULTI_JUDGE_3_WORKFLOW,
32
+ ];
33
+ const map = {};
34
+ for (const cfg of configs) {
35
+ map[cfg.id] = cfg;
36
+ }
37
+ return map;
38
+ }
39
+ /**
40
+ * Workflow CLI command factory
41
+ */
42
+ export class WorkflowCommandFactory {
43
+ static createWorkflowCommands() {
44
+ return {
45
+ command: "workflow <subcommand>",
46
+ describe: "Manage and execute AI workflows",
47
+ builder: (yargs) => {
48
+ return yargs
49
+ .command("list", "List available predefined workflows", (y) => y, async () => {
50
+ await WorkflowCommandFactory.executeList();
51
+ })
52
+ .command("info <name>", "Show details of a workflow", (y) => y.positional("name", {
53
+ type: "string",
54
+ description: "Workflow name/id",
55
+ demandOption: true,
56
+ }), async (argv) => {
57
+ await WorkflowCommandFactory.executeInfo(argv);
58
+ })
59
+ .command("execute <name> <prompt>", "Execute a workflow with a prompt", (y) => y
60
+ .positional("name", {
61
+ type: "string",
62
+ description: "Workflow name/id",
63
+ demandOption: true,
64
+ })
65
+ .positional("prompt", {
66
+ type: "string",
67
+ description: "Prompt to send to the workflow",
68
+ demandOption: true,
69
+ })
70
+ .option("provider", {
71
+ type: "string",
72
+ description: "Override AI provider",
73
+ })
74
+ .option("model", {
75
+ type: "string",
76
+ description: "Override model name",
77
+ })
78
+ .option("timeout", {
79
+ type: "number",
80
+ description: "Execution timeout in milliseconds",
81
+ })
82
+ .option("verbose", {
83
+ type: "boolean",
84
+ description: "Enable verbose output",
85
+ default: false,
86
+ }), async (argv) => {
87
+ await WorkflowCommandFactory.executeWorkflow(argv);
88
+ })
89
+ .demandCommand(1, "Please specify a workflow subcommand");
90
+ },
91
+ handler: () => { },
92
+ };
93
+ }
94
+ /**
95
+ * List all predefined workflows
96
+ */
97
+ static async executeList() {
98
+ const workflows = await loadPredefinedWorkflows();
99
+ const configs = Object.values(workflows);
100
+ console.info(chalk.bold("\nAvailable Workflows:\n"));
101
+ for (const cfg of configs) {
102
+ const tags = cfg.tags?.join(", ") || "";
103
+ console.info(` ${chalk.cyan(cfg.id.padEnd(24))} ${chalk.white(cfg.name)}`);
104
+ console.info(` ${"".padEnd(24)} ${chalk.gray(cfg.description || "")}`);
105
+ if (tags) {
106
+ console.info(` ${"".padEnd(24)} ${chalk.gray(`Tags: ${tags}`)}`);
107
+ }
108
+ console.info();
109
+ }
110
+ console.info(chalk.gray(`Total: ${configs.length} workflows`));
111
+ }
112
+ /**
113
+ * Show details of a specific workflow
114
+ */
115
+ static async executeInfo(argv) {
116
+ const workflows = await loadPredefinedWorkflows();
117
+ const cfg = workflows[argv.name];
118
+ if (!cfg) {
119
+ console.error(chalk.red(`Workflow "${argv.name}" not found.`));
120
+ console.info(chalk.gray(`Available: ${Object.keys(workflows).join(", ")}`));
121
+ process.exitCode = 1;
122
+ return;
123
+ }
124
+ console.info(chalk.bold(`\nWorkflow: ${cfg.name}\n`));
125
+ console.info(` ID: ${cfg.id}`);
126
+ console.info(` Type: ${cfg.type}`);
127
+ console.info(` Version: ${cfg.version || "n/a"}`);
128
+ console.info(` Description: ${cfg.description || "n/a"}`);
129
+ if (cfg.models && cfg.models.length > 0) {
130
+ console.info(`\n Models:`);
131
+ for (const m of cfg.models) {
132
+ console.info(` - ${chalk.cyan(m.label || m.model)} (${m.provider})`);
133
+ }
134
+ }
135
+ if (cfg.modelGroups && cfg.modelGroups.length > 0) {
136
+ console.info(`\n Model Groups:`);
137
+ for (const group of cfg.modelGroups) {
138
+ console.info(` ${chalk.cyan(group.id)}:`);
139
+ for (const m of group.models) {
140
+ console.info(` - ${m.label || m.model} (${m.provider})`);
141
+ }
142
+ }
143
+ }
144
+ if (cfg.judge) {
145
+ console.info(`\n Judge: ${cfg.judge.model} (${cfg.judge.provider})`);
146
+ if (cfg.judge.criteria) {
147
+ console.info(` Criteria: ${cfg.judge.criteria.join(", ")}`);
148
+ }
149
+ }
150
+ if (cfg.execution) {
151
+ console.info(`\n Execution:`);
152
+ if (cfg.execution.timeout) {
153
+ console.info(` Timeout: ${cfg.execution.timeout}ms`);
154
+ }
155
+ if (cfg.execution.parallelism) {
156
+ console.info(` Parallelism: ${cfg.execution.parallelism}`);
157
+ }
158
+ if (cfg.execution.minResponses) {
159
+ console.info(` Min Responses: ${cfg.execution.minResponses}`);
160
+ }
161
+ }
162
+ if (cfg.tags && cfg.tags.length > 0) {
163
+ console.info(`\n Tags: ${cfg.tags.join(", ")}`);
164
+ }
165
+ }
166
+ /**
167
+ * Execute a workflow
168
+ */
169
+ static async executeWorkflow(argv) {
170
+ const workflows = await loadPredefinedWorkflows();
171
+ let cfg = workflows[argv.name];
172
+ if (!cfg) {
173
+ console.error(chalk.red(`Workflow "${argv.name}" not found.`));
174
+ console.info(chalk.gray(`Available: ${Object.keys(workflows).join(", ")}`));
175
+ process.exitCode = 1;
176
+ return;
177
+ }
178
+ // Apply provider/model overrides if specified
179
+ if (argv.provider || argv.model) {
180
+ cfg = {
181
+ ...cfg,
182
+ models: cfg.models?.map((m) => ({
183
+ ...m,
184
+ provider: argv.provider || m.provider,
185
+ model: argv.model || m.model,
186
+ })),
187
+ };
188
+ }
189
+ const spinner = ora("Executing workflow...").start();
190
+ try {
191
+ const { runWorkflow } = await import("../../lib/workflow/core/workflowRunner.js");
192
+ const result = await runWorkflow(cfg, {
193
+ prompt: argv.prompt,
194
+ timeout: argv.timeout,
195
+ verbose: argv.verbose,
196
+ });
197
+ spinner.stop();
198
+ if (result.content) {
199
+ console.info(result.content);
200
+ }
201
+ else {
202
+ console.info(chalk.yellow("Workflow completed but produced no content."));
203
+ if (result.reasoning) {
204
+ console.info(chalk.gray(`Reasoning: ${result.reasoning}`));
205
+ }
206
+ }
207
+ }
208
+ catch (error) {
209
+ spinner.stop();
210
+ const msg = error instanceof Error ? error.message : String(error);
211
+ console.error(chalk.red(`Workflow execution failed: ${msg}`));
212
+ process.exitCode = 1;
213
+ }
214
+ }
215
+ }
216
+ //# sourceMappingURL=workflow.js.map
@@ -335,7 +335,7 @@ export class CLICommandFactory {
335
335
  },
336
336
  thinkingLevel: {
337
337
  type: "string",
338
- description: "Thinking level for Gemini 3 models: minimal, low, medium, high",
338
+ description: "Thinking level for extended reasoning (Anthropic Claude, Gemini 2.5+, Gemini 3): minimal, low, medium, high",
339
339
  choices: ["minimal", "low", "medium", "high"],
340
340
  },
341
341
  region: {
@@ -609,17 +609,10 @@ export class CLICommandFactory {
609
609
  try {
610
610
  // Use custom path or default
611
611
  let imagePath;
612
- const cwd = process.cwd();
613
612
  if (options.imageOutput) {
614
- imagePath = options.imageOutput;
615
- // Validate path is within current working directory for security
616
- const resolvedPath = path.resolve(imagePath);
617
- if (!resolvedPath.startsWith(cwd + path.sep) &&
618
- resolvedPath !== cwd) {
619
- throw new Error(`Image output path must be within current directory: ${cwd}`);
620
- }
613
+ imagePath = path.resolve(options.imageOutput);
621
614
  // Create parent directory if needed (cross-platform)
622
- const dir = path.dirname(resolvedPath);
615
+ const dir = path.dirname(imagePath);
623
616
  if (dir && dir !== "." && !fs.existsSync(dir)) {
624
617
  fs.mkdirSync(dir, { recursive: true });
625
618
  }
@@ -1648,6 +1641,20 @@ export class CLICommandFactory {
1648
1641
  topK: argv.ragTopK,
1649
1642
  }
1650
1643
  : undefined,
1644
+ // TTS configuration
1645
+ tts: enhancedOptions.tts
1646
+ ? {
1647
+ enabled: true,
1648
+ useAiResponse: true,
1649
+ voice: enhancedOptions.ttsVoice,
1650
+ format: enhancedOptions.ttsFormat ||
1651
+ undefined,
1652
+ speed: enhancedOptions.ttsSpeed,
1653
+ quality: enhancedOptions.ttsQuality,
1654
+ output: enhancedOptions.ttsOutput,
1655
+ play: enhancedOptions.ttsPlay,
1656
+ }
1657
+ : undefined,
1651
1658
  });
1652
1659
  if (spinner) {
1653
1660
  if (isVideoMode) {
@@ -1865,16 +1872,59 @@ export class CLICommandFactory {
1865
1872
  topK: argv.ragTopK,
1866
1873
  }
1867
1874
  : undefined,
1875
+ // TTS configuration
1876
+ tts: enhancedOptions.tts
1877
+ ? {
1878
+ enabled: true,
1879
+ useAiResponse: true,
1880
+ voice: enhancedOptions.ttsVoice,
1881
+ format: enhancedOptions.ttsFormat ||
1882
+ undefined,
1883
+ speed: enhancedOptions.ttsSpeed,
1884
+ quality: enhancedOptions.ttsQuality,
1885
+ output: enhancedOptions.ttsOutput,
1886
+ play: enhancedOptions.ttsPlay,
1887
+ }
1888
+ : undefined,
1868
1889
  });
1869
- const fullContent = await CLICommandFactory.processStreamWithTimeout(stream, options);
1870
- await CLICommandFactory.displayStreamResults(stream, fullContent, options);
1871
- return fullContent;
1890
+ const streamResult = await CLICommandFactory.processStreamWithTimeout(stream, options);
1891
+ await CLICommandFactory.displayStreamResults(stream, streamResult.content, options);
1892
+ // Handle image output from stream (image models emit image events)
1893
+ if (streamResult.imageBase64) {
1894
+ try {
1895
+ let imagePath;
1896
+ if (options.imageOutput) {
1897
+ imagePath = path.resolve(options.imageOutput);
1898
+ const dir = path.dirname(imagePath);
1899
+ if (dir && dir !== "." && !fs.existsSync(dir)) {
1900
+ fs.mkdirSync(dir, { recursive: true });
1901
+ }
1902
+ }
1903
+ else {
1904
+ const imageDir = "generated-images";
1905
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
1906
+ imagePath = path.join(imageDir, `image-${timestamp}.png`);
1907
+ if (!fs.existsSync(imageDir)) {
1908
+ fs.mkdirSync(imageDir, { recursive: true });
1909
+ }
1910
+ }
1911
+ const imageBuffer = Buffer.from(streamResult.imageBase64, "base64");
1912
+ fs.writeFileSync(imagePath, imageBuffer);
1913
+ logger.always(`\nšŸ“ø Generated image saved to: ${imagePath}`);
1914
+ logger.always(` Image size: ${(imageBuffer.length / 1024).toFixed(2)} KB`);
1915
+ }
1916
+ catch (error) {
1917
+ handleError(error, "Failed to save streamed image");
1918
+ }
1919
+ }
1920
+ return streamResult.content;
1872
1921
  }
1873
1922
  /**
1874
1923
  * Process stream with timeout handling
1875
1924
  */
1876
1925
  static async processStreamWithTimeout(stream, options) {
1877
1926
  let fullContent = "";
1927
+ let lastImageBase64;
1878
1928
  let contentReceived = false;
1879
1929
  const abortController = new AbortController();
1880
1930
  // Create timeout promise for stream consumption (default: 30 seconds, respects user-provided timeout)
@@ -1934,10 +1984,20 @@ export class CLICommandFactory {
1934
1984
  const isAudio = (o) => !!o &&
1935
1985
  typeof o === "object" &&
1936
1986
  o.type === "audio";
1937
- const isImage = (o) => !!o &&
1938
- typeof o === "object" &&
1939
- o.type === "image" &&
1940
- typeof o.imageOutput === "object";
1987
+ const isImage = (o) => {
1988
+ if (!o || typeof o !== "object") {
1989
+ return false;
1990
+ }
1991
+ const record = o;
1992
+ if (record.type !== "image") {
1993
+ return false;
1994
+ }
1995
+ if (!record.imageOutput || typeof record.imageOutput !== "object") {
1996
+ return false;
1997
+ }
1998
+ return (typeof record.imageOutput.base64 ===
1999
+ "string");
2000
+ };
1941
2001
  if (isText(evt)) {
1942
2002
  process.stdout.write(evt.content);
1943
2003
  fullContent += evt.content;
@@ -1948,8 +2008,7 @@ export class CLICommandFactory {
1948
2008
  }
1949
2009
  }
1950
2010
  else if (isImage(evt)) {
1951
- // Image events are handled after stream completes (in generate flow)
1952
- // This handler ensures they're not silently dropped
2011
+ lastImageBase64 = evt.imageOutput.base64;
1953
2012
  if (options.debug && !options.quiet) {
1954
2013
  process.stdout.write("[image-received]");
1955
2014
  }
@@ -1967,7 +2026,7 @@ export class CLICommandFactory {
1967
2026
  if (!options.quiet) {
1968
2027
  process.stdout.write("\n");
1969
2028
  }
1970
- return fullContent;
2029
+ return { content: fullContent, imageBase64: lastImageBase64 };
1971
2030
  }
1972
2031
  /**
1973
2032
  * Display analytics and evaluation results
package/dist/cli/index.js CHANGED
@@ -26,7 +26,6 @@ catch {
26
26
  // Environment variables should be set externally in production
27
27
  }
28
28
  // Enhanced CLI with Professional UX
29
- // Note: Workflow functionality is accessed via generate/stream commands with --workflow-config option
30
29
  const cli = initializeCliParser();
31
30
  // Execute CLI
32
31
  (async () => {