@juspay/neurolink 9.83.0 → 9.84.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 (117) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/agent/agent.d.ts +104 -0
  3. package/dist/agent/agent.js +401 -0
  4. package/dist/agent/agentNetwork.d.ts +87 -0
  5. package/dist/agent/agentNetwork.js +458 -0
  6. package/dist/agent/communication/index.d.ts +9 -0
  7. package/dist/agent/communication/index.js +9 -0
  8. package/dist/agent/communication/message-bus.d.ts +113 -0
  9. package/dist/agent/communication/message-bus.js +406 -0
  10. package/dist/agent/coordination/coordinator.d.ts +83 -0
  11. package/dist/agent/coordination/coordinator.js +598 -0
  12. package/dist/agent/coordination/index.d.ts +10 -0
  13. package/dist/agent/coordination/index.js +10 -0
  14. package/dist/agent/coordination/task-distributor.d.ts +113 -0
  15. package/dist/agent/coordination/task-distributor.js +585 -0
  16. package/dist/agent/index.d.ts +38 -0
  17. package/dist/agent/index.js +44 -0
  18. package/dist/agent/orchestration/index.d.ts +10 -0
  19. package/dist/agent/orchestration/index.js +10 -0
  20. package/dist/agent/orchestration/orchestrator.d.ts +114 -0
  21. package/dist/agent/orchestration/orchestrator.js +476 -0
  22. package/dist/agent/orchestration/topology.d.ts +164 -0
  23. package/dist/agent/orchestration/topology.js +520 -0
  24. package/dist/agent/prompts/routingPrompts.d.ts +63 -0
  25. package/dist/agent/prompts/routingPrompts.js +201 -0
  26. package/dist/browser/neurolink.min.js +377 -358
  27. package/dist/cli/commands/agent.d.ts +37 -0
  28. package/dist/cli/commands/agent.js +718 -0
  29. package/dist/cli/factories/commandFactory.d.ts +8 -0
  30. package/dist/cli/factories/commandFactory.js +116 -0
  31. package/dist/cli/loop/optionsSchema.d.ts +1 -1
  32. package/dist/cli/parser.js +4 -0
  33. package/dist/index.d.ts +6 -0
  34. package/dist/index.js +19 -0
  35. package/dist/lib/agent/agent.d.ts +104 -0
  36. package/dist/lib/agent/agent.js +402 -0
  37. package/dist/lib/agent/agentNetwork.d.ts +87 -0
  38. package/dist/lib/agent/agentNetwork.js +459 -0
  39. package/dist/lib/agent/communication/index.d.ts +9 -0
  40. package/dist/lib/agent/communication/index.js +10 -0
  41. package/dist/lib/agent/communication/message-bus.d.ts +113 -0
  42. package/dist/lib/agent/communication/message-bus.js +407 -0
  43. package/dist/lib/agent/coordination/coordinator.d.ts +83 -0
  44. package/dist/lib/agent/coordination/coordinator.js +599 -0
  45. package/dist/lib/agent/coordination/index.d.ts +10 -0
  46. package/dist/lib/agent/coordination/index.js +11 -0
  47. package/dist/lib/agent/coordination/task-distributor.d.ts +113 -0
  48. package/dist/lib/agent/coordination/task-distributor.js +586 -0
  49. package/dist/lib/agent/index.d.ts +38 -0
  50. package/dist/lib/agent/index.js +45 -0
  51. package/dist/lib/agent/orchestration/index.d.ts +10 -0
  52. package/dist/lib/agent/orchestration/index.js +11 -0
  53. package/dist/lib/agent/orchestration/orchestrator.d.ts +114 -0
  54. package/dist/lib/agent/orchestration/orchestrator.js +477 -0
  55. package/dist/lib/agent/orchestration/topology.d.ts +164 -0
  56. package/dist/lib/agent/orchestration/topology.js +521 -0
  57. package/dist/lib/agent/prompts/routingPrompts.d.ts +63 -0
  58. package/dist/lib/agent/prompts/routingPrompts.js +202 -0
  59. package/dist/lib/index.d.ts +6 -0
  60. package/dist/lib/index.js +19 -0
  61. package/dist/lib/neurolink.d.ts +129 -0
  62. package/dist/lib/neurolink.js +276 -0
  63. package/dist/lib/processors/config/{fileTypes.js → fileExtensions.js} +1 -1
  64. package/dist/lib/processors/config/index.d.ts +2 -2
  65. package/dist/lib/processors/config/index.js +2 -2
  66. package/dist/lib/processors/config/{mimeTypes.js → mimeConstants.js} +1 -1
  67. package/dist/lib/processors/index.js +8 -0
  68. package/dist/lib/providers/googleAiStudio.js +3 -3
  69. package/dist/lib/providers/googleNativeGemini3.d.ts +18 -0
  70. package/dist/lib/providers/googleNativeGemini3.js +47 -1
  71. package/dist/lib/providers/googleVertex.js +5 -5
  72. package/dist/lib/types/agentNetwork.d.ts +1184 -0
  73. package/dist/lib/types/agentNetwork.js +8 -0
  74. package/dist/lib/types/cli.d.ts +66 -0
  75. package/dist/lib/types/generate.d.ts +53 -0
  76. package/dist/lib/types/index.d.ts +2 -0
  77. package/dist/lib/types/index.js +3 -0
  78. package/dist/lib/types/ioProcessor.d.ts +119 -0
  79. package/dist/lib/types/ioProcessor.js +10 -0
  80. package/dist/lib/types/stream.d.ts +36 -0
  81. package/dist/lib/utils/piiDetector.d.ts +24 -0
  82. package/dist/lib/utils/piiDetector.js +221 -0
  83. package/dist/lib/utils/responseValidator.d.ts +21 -0
  84. package/dist/lib/utils/responseValidator.js +354 -0
  85. package/dist/lib/utils/tripwireEvaluator.d.ts +73 -0
  86. package/dist/lib/utils/tripwireEvaluator.js +285 -0
  87. package/dist/neurolink.d.ts +129 -0
  88. package/dist/neurolink.js +276 -0
  89. package/dist/processors/config/index.d.ts +2 -2
  90. package/dist/processors/config/index.js +2 -2
  91. package/dist/processors/index.js +8 -0
  92. package/dist/providers/googleAiStudio.js +3 -3
  93. package/dist/providers/googleNativeGemini3.d.ts +18 -0
  94. package/dist/providers/googleNativeGemini3.js +47 -1
  95. package/dist/providers/googleVertex.js +5 -5
  96. package/dist/types/agentNetwork.d.ts +1184 -0
  97. package/dist/types/agentNetwork.js +7 -0
  98. package/dist/types/cli.d.ts +66 -0
  99. package/dist/types/generate.d.ts +53 -0
  100. package/dist/types/index.d.ts +2 -0
  101. package/dist/types/index.js +3 -0
  102. package/dist/types/ioProcessor.d.ts +119 -0
  103. package/dist/types/ioProcessor.js +9 -0
  104. package/dist/types/stream.d.ts +36 -0
  105. package/dist/utils/piiDetector.d.ts +24 -0
  106. package/dist/utils/piiDetector.js +220 -0
  107. package/dist/utils/responseValidator.d.ts +21 -0
  108. package/dist/utils/responseValidator.js +353 -0
  109. package/dist/utils/tripwireEvaluator.d.ts +73 -0
  110. package/dist/utils/tripwireEvaluator.js +284 -0
  111. package/package.json +1 -1
  112. /package/dist/lib/processors/config/{fileTypes.d.ts → fileExtensions.d.ts} +0 -0
  113. /package/dist/lib/processors/config/{mimeTypes.d.ts → mimeConstants.d.ts} +0 -0
  114. /package/dist/processors/config/{fileTypes.d.ts → fileExtensions.d.ts} +0 -0
  115. /package/dist/processors/config/{fileTypes.js → fileExtensions.js} +0 -0
  116. /package/dist/processors/config/{mimeTypes.d.ts → mimeConstants.d.ts} +0 -0
  117. /package/dist/processors/config/{mimeTypes.js → mimeConstants.js} +0 -0
package/dist/neurolink.js CHANGED
@@ -90,6 +90,8 @@ import { runWorkflow } from "./workflow/core/workflowRunner.js";
90
90
  import { ModelPool, classifyProviderError } from "./routing/index.js";
91
91
  import { ClassifierRouter } from "./routing/classifierRouter.js";
92
92
  import { looksLikeModelAccessDenied as sharedLooksLikeModelAccessDenied, isNonRetryableProviderError as sharedIsNonRetryableProviderError, } from "./utils/providerErrorClassification.js";
93
+ import { detectAndRedactPII } from "./utils/piiDetector.js";
94
+ import { validateResponse } from "./utils/responseValidator.js";
93
95
  /**
94
96
  * NL-002: Classify MCP error messages into categories for AI disambiguation.
95
97
  * Returns a human-readable error category based on error message content.
@@ -3063,6 +3065,41 @@ Current user's request: ${currentInput}`;
3063
3065
  if (!hasSttAudio && !isMediaModalityMode) {
3064
3066
  this.assertInputText(options.input?.text, "Input text is required and must be a non-empty string");
3065
3067
  }
3068
+ // Input validation (trimWhitespace, minLength, maxLength, requireContent).
3069
+ // Guard on a string input.text — release's media-only / STT flows may leave
3070
+ // it empty/undefined, and those never carry inputValidation anyway.
3071
+ if (options.inputValidation && typeof options.input.text === "string") {
3072
+ const iv = options.inputValidation;
3073
+ if (iv.trimWhitespace) {
3074
+ options.input.text = options.input.text.trim();
3075
+ }
3076
+ if (iv.requireContent && !options.input.text.trim()) {
3077
+ throw new Error("Input content is required but was empty or whitespace");
3078
+ }
3079
+ if (iv.minLength && options.input.text.length < iv.minLength) {
3080
+ throw new Error(`Input text is too short (${options.input.text.length} < ${iv.minLength})`);
3081
+ }
3082
+ if (iv.maxLength && options.input.text.length > iv.maxLength) {
3083
+ throw new Error(`Input text is too long (${options.input.text.length} > ${iv.maxLength})`);
3084
+ }
3085
+ }
3086
+ // PII detection and redaction
3087
+ if (options.piiDetection?.enabled &&
3088
+ typeof options.input.text === "string") {
3089
+ const piiResult = await detectAndRedactPII(options.input.text, {
3090
+ enabled: true,
3091
+ action: options.piiDetection.action ?? "warn",
3092
+ detectTypes: options.piiDetection.detectTypes,
3093
+ customPatterns: options.piiDetection.customPatterns,
3094
+ allowList: options.piiDetection.allowList,
3095
+ redactionText: options.piiDetection.redactionText,
3096
+ });
3097
+ if (piiResult.action === "abort") {
3098
+ throw new Error(piiResult.feedback ?? "Request blocked: PII detected in input");
3099
+ }
3100
+ // Replace input text with redacted version
3101
+ options.input.text = piiResult.text;
3102
+ }
3066
3103
  this.enforceSessionBudget(options.maxBudgetUsd);
3067
3104
  this.applyGenerateLifecycleMiddleware(options);
3068
3105
  await this.applyAuthenticatedRequestContext(options);
@@ -3702,6 +3739,29 @@ Current user's request: ${currentInput}`;
3702
3739
  reasoningTokens: textResult.reasoningTokens,
3703
3740
  ...(textResult.retries && { retries: textResult.retries }),
3704
3741
  };
3742
+ // Response validation (if configured)
3743
+ if (options.responseValidation) {
3744
+ const validationResult = validateResponse(generateResult.content ?? "", {
3745
+ minLength: options.responseValidation.minLength,
3746
+ maxLength: options.responseValidation.maxLength,
3747
+ requiredPhrases: options.responseValidation.requiredPhrases,
3748
+ forbiddenPhrases: options.responseValidation.forbiddenPhrases,
3749
+ jsonSchema: options.responseValidation.jsonSchema,
3750
+ customValidator: options.responseValidation.customValidator,
3751
+ truncationAction: options.responseValidation.truncationAction,
3752
+ truncationSuffix: options.responseValidation.truncationSuffix,
3753
+ retryOnFailure: options.responseValidation.retryOnFailure,
3754
+ maxRetries: options.responseValidation.maxRetries,
3755
+ });
3756
+ if (validationResult.action === "abort") {
3757
+ throw new Error(validationResult.feedback ??
3758
+ `Response validation failed: ${validationResult.issues.map((i) => i.message).join("; ")}`);
3759
+ }
3760
+ // Apply validated/truncated text
3761
+ if (validationResult.text !== generateResult.content) {
3762
+ generateResult.content = validationResult.text;
3763
+ }
3764
+ }
3705
3765
  if (generateResult.analytics?.cost && generateResult.analytics.cost > 0) {
3706
3766
  this._sessionCostUsd += generateResult.analytics.cost;
3707
3767
  }
@@ -6452,6 +6512,37 @@ Current user's request: ${currentInput}`;
6452
6512
  }
6453
6513
  async validateStreamRequestOptions(options, startTime) {
6454
6514
  await this.validateStreamInput(options);
6515
+ // Input validation for stream
6516
+ if (options.inputValidation && options.input?.text) {
6517
+ const iv = options.inputValidation;
6518
+ if (iv.trimWhitespace) {
6519
+ options.input.text = options.input.text.trim();
6520
+ }
6521
+ if (iv.requireContent && !options.input.text.trim()) {
6522
+ throw new Error("Input content is required but was empty or whitespace");
6523
+ }
6524
+ if (iv.minLength && options.input.text.length < iv.minLength) {
6525
+ throw new Error(`Input text is too short (${options.input.text.length} < ${iv.minLength})`);
6526
+ }
6527
+ if (iv.maxLength && options.input.text.length > iv.maxLength) {
6528
+ throw new Error(`Input text is too long (${options.input.text.length} > ${iv.maxLength})`);
6529
+ }
6530
+ }
6531
+ // PII detection and redaction for stream
6532
+ if (options.piiDetection?.enabled && options.input?.text) {
6533
+ const piiResult = await detectAndRedactPII(options.input.text, {
6534
+ enabled: true,
6535
+ action: options.piiDetection.action ?? "warn",
6536
+ detectTypes: options.piiDetection.detectTypes,
6537
+ customPatterns: options.piiDetection.customPatterns,
6538
+ allowList: options.piiDetection.allowList,
6539
+ redactionText: options.piiDetection.redactionText,
6540
+ });
6541
+ if (piiResult.action === "abort") {
6542
+ throw new Error(piiResult.feedback ?? "Request blocked: PII detected in input");
6543
+ }
6544
+ options.input.text = piiResult.text;
6545
+ }
6455
6546
  this.enforceSessionBudget(options.maxBudgetUsd);
6456
6547
  await this.applyAuthenticatedRequestContext(options);
6457
6548
  this.emitStreamStartEvents(options, startTime);
@@ -11216,6 +11307,191 @@ Current user's request: ${currentInput}`;
11216
11307
  const { getPreset } = await withTimeout(import("./evaluation/pipeline/index.js"), 10000, ErrorFactory.evaluationTimeout("evaluation module load", 10000));
11217
11308
  return getPreset(presetName);
11218
11309
  }
11310
+ // ============================================================================
11311
+ // MULTI-AGENT ORCHESTRATION METHODS
11312
+ // ============================================================================
11313
+ /**
11314
+ * Create an Agent instance for multi-agent orchestration.
11315
+ *
11316
+ * Agents are specialized AI entities with defined instructions, tools, and behavior.
11317
+ * They can be composed into networks for complex task orchestration.
11318
+ *
11319
+ * @param definition - Agent definition specifying behavior and capabilities
11320
+ * @returns A new Agent instance
11321
+ *
11322
+ * @example
11323
+ * ```typescript
11324
+ * const researcher = neurolink.createAgent({
11325
+ * id: 'researcher',
11326
+ * name: 'Research Agent',
11327
+ * description: 'Searches and analyzes information from various sources',
11328
+ * instructions: 'You are a research assistant. Search thoroughly and cite sources.',
11329
+ * tools: ['websearchGrounding', 'readFile'],
11330
+ * model: 'gpt-4o'
11331
+ * });
11332
+ *
11333
+ * const result = await researcher.execute('Find recent AI breakthroughs');
11334
+ * ```
11335
+ *
11336
+ * @see {@link AgentDefinition} for definition options
11337
+ * @see {@link Agent} for agent methods
11338
+ * @since 8.38.0
11339
+ */
11340
+ async createAgent(definition) {
11341
+ const { Agent } = await import("./agent/agent.js");
11342
+ logger.debug("[NeuroLink] Creating agent", {
11343
+ id: definition.id,
11344
+ name: definition.name,
11345
+ tools: definition.tools?.length || 0,
11346
+ });
11347
+ return new Agent(definition, this);
11348
+ }
11349
+ /**
11350
+ * Create an AgentNetwork for multi-agent orchestration.
11351
+ *
11352
+ * Networks coordinate multiple agents, workflows, and tools with intelligent
11353
+ * LLM-powered routing. The router agent analyzes tasks and delegates to
11354
+ * the most appropriate primitive.
11355
+ *
11356
+ * @param config - Network configuration with agents, workflows, and routing settings
11357
+ * @returns A new AgentNetwork instance
11358
+ *
11359
+ * @example
11360
+ * ```typescript
11361
+ * const network = neurolink.createNetwork({
11362
+ * name: 'Content Team',
11363
+ * description: 'Collaborative content creation pipeline',
11364
+ * agents: [
11365
+ * {
11366
+ * id: 'researcher',
11367
+ * name: 'Researcher',
11368
+ * description: 'Finds and verifies information',
11369
+ * instructions: 'Research topics thoroughly...',
11370
+ * },
11371
+ * {
11372
+ * id: 'writer',
11373
+ * name: 'Writer',
11374
+ * description: 'Creates engaging content',
11375
+ * instructions: 'Write clear, engaging content...',
11376
+ * },
11377
+ * {
11378
+ * id: 'editor',
11379
+ * name: 'Editor',
11380
+ * description: 'Reviews and improves content',
11381
+ * instructions: 'Review for clarity and accuracy...',
11382
+ * }
11383
+ * ],
11384
+ * router: {
11385
+ * model: 'gpt-4o',
11386
+ * confidenceThreshold: 0.7
11387
+ * }
11388
+ * });
11389
+ *
11390
+ * const result = await network.execute({
11391
+ * message: 'Write an article about quantum computing'
11392
+ * });
11393
+ * ```
11394
+ *
11395
+ * @see {@link AgentNetworkConfig} for configuration options
11396
+ * @see {@link AgentNetwork} for network methods
11397
+ * @since 8.38.0
11398
+ */
11399
+ async createNetwork(config) {
11400
+ const { AgentNetwork } = await import("./agent/agentNetwork.js");
11401
+ logger.debug("[NeuroLink] Creating agent network", {
11402
+ name: config.name,
11403
+ agentCount: config.agents.length,
11404
+ workflowCount: config.workflows?.length || 0,
11405
+ toolCount: config.tools?.length || 0,
11406
+ });
11407
+ return new AgentNetwork(config, this);
11408
+ }
11409
+ /**
11410
+ * Execute an agent network with the given input.
11411
+ *
11412
+ * @param network - The agent network to execute
11413
+ * @param input - Execution input (message and context)
11414
+ * @param options - Optional execution options
11415
+ * @returns Network execution result with content, trace, and usage
11416
+ *
11417
+ * @see {@link NetworkExecutionInput} for input options
11418
+ * @see {@link NetworkExecutionResult} for result structure
11419
+ * @since 8.38.0
11420
+ */
11421
+ async executeNetwork(network, input, options) {
11422
+ logger.debug("[NeuroLink] Executing agent network", {
11423
+ networkId: network.id,
11424
+ networkName: network.name,
11425
+ hasContext: !!input.context,
11426
+ });
11427
+ return network.execute(input, options);
11428
+ }
11429
+ /**
11430
+ * Stream agent network execution with real-time events.
11431
+ *
11432
+ * @param network - The agent network to stream
11433
+ * @param input - Execution input (message and context)
11434
+ * @param options - Optional execution options
11435
+ * @returns Async iterable of network stream chunks
11436
+ *
11437
+ * @see {@link NetworkStreamChunk} for chunk types
11438
+ * @since 8.38.0
11439
+ */
11440
+ async *streamNetwork(network, input, options) {
11441
+ logger.debug("[NeuroLink] Streaming agent network", {
11442
+ networkId: network.id,
11443
+ networkName: network.name,
11444
+ hasContext: !!input.context,
11445
+ });
11446
+ yield* network.stream(input, options);
11447
+ }
11448
+ // ============================================================================
11449
+ // ADVANCED ORCHESTRATION METHODS
11450
+ // ============================================================================
11451
+ /**
11452
+ * Create a NetworkOrchestrator for managing multiple agent networks.
11453
+ *
11454
+ * @param config - Orchestrator configuration options
11455
+ * @returns A new NetworkOrchestrator instance
11456
+ * @since 8.38.0
11457
+ */
11458
+ async createOrchestrator(config) {
11459
+ const { NetworkOrchestrator } = await import("./agent/orchestration/index.js");
11460
+ logger.debug("[NeuroLink] Creating network orchestrator", {
11461
+ maxConcurrentExecutions: config?.maxConcurrentExecutions,
11462
+ defaultMode: config?.defaultMode,
11463
+ });
11464
+ return new NetworkOrchestrator(this, config);
11465
+ }
11466
+ /**
11467
+ * Create an AgentCoordinator for managing agent coordination strategies.
11468
+ *
11469
+ * @param config - Coordinator configuration options
11470
+ * @returns A new AgentCoordinator instance
11471
+ * @since 8.38.0
11472
+ */
11473
+ async createCoordinator(config) {
11474
+ const { AgentCoordinator } = await import("./agent/coordination/index.js");
11475
+ logger.debug("[NeuroLink] Creating agent coordinator", {
11476
+ strategy: config?.strategy,
11477
+ maxConcurrency: config?.maxConcurrency,
11478
+ });
11479
+ return new AgentCoordinator(config);
11480
+ }
11481
+ /**
11482
+ * Create a MessageBus for inter-agent communication.
11483
+ *
11484
+ * @param config - Message bus configuration options
11485
+ * @returns A new MessageBus instance
11486
+ * @since 8.38.0
11487
+ */
11488
+ async createMessageBus(config) {
11489
+ const { MessageBus } = await import("./agent/communication/index.js");
11490
+ logger.debug("[NeuroLink] Creating message bus", {
11491
+ maxHistorySize: config?.maxHistorySize,
11492
+ });
11493
+ return new MessageBus(config);
11494
+ }
11219
11495
  /**
11220
11496
  * Dispose of all resources and cleanup connections
11221
11497
  * Call this method when done using the NeuroLink instance to prevent resource leaks
@@ -26,7 +26,7 @@
26
26
  * const maxSize = SIZE_LIMITS.IMAGE_MAX_MB; // 10
27
27
  * ```
28
28
  */
29
- export { ARCHIVE_MIME_TYPES, AUDIO_MIME_TYPES, DATA_MIME_TYPES, DOCUMENT_MIME_TYPES, EXTENSION_MIME_MAP, getMimeTypeForExtension, IMAGE_MIME_TYPES, MIME_TYPES, SOURCE_CODE_MIME_TYPES, TEXT_MIME_TYPES, VIDEO_MIME_TYPES, } from "./mimeTypes.js";
30
- export { ADA_EXTENSIONS, AI_VISION_EXTENSIONS, ARCHIVE_EXTENSIONS, ASSEMBLY_EXTENSIONS, AUDIO_EXTENSIONS, C_EXTENSIONS, CLOJURE_EXTENSIONS, COBOL_EXTENSIONS, CONFIG_EXTENSIONS, CPP_EXTENSIONS, CRYSTAL_EXTENSIONS, CSHARP_EXTENSIONS, CSS_EXTENSIONS, CSV_EXTENSIONS, D_EXTENSIONS, DART_EXTENSIONS, DATA_EXTENSIONS, DATABASE_EXTENSIONS, DESIGN_EXTENSIONS, DOCKERFILE_EXTENSIONS, DOCUMENT_EXTENSIONS, EJS_EXTENSIONS, ELIXIR_EXTENSIONS, ERLANG_EXTENSIONS, EXCEL_EXTENSIONS, EXECUTABLE_EXTENSIONS, FILE_EXTENSIONS, FORTRAN_EXTENSIONS, FSHARP_EXTENSIONS, GO_EXTENSIONS, GROOVY_EXTENSIONS, HANDLEBARS_EXTENSIONS, HASKELL_EXTENSIONS, HTML_EXTENSIONS, IMAGE_EXTENSIONS, JAVA_EXTENSIONS, JAVASCRIPT_EXTENSIONS, JSON_EXTENSIONS, JULIA_EXTENSIONS, KOTLIN_EXTENSIONS, LESS_EXTENSIONS, LISP_EXTENSIONS, LUA_EXTENSIONS, MAKEFILE_EXTENSIONS, MARKDOWN_EXTENSIONS, NIM_EXTENSIONS, OBJECTIVE_C_EXTENSIONS, OCAML_EXTENSIONS, OPENDOCUMENT_EXTENSIONS, PASCAL_EXTENSIONS, PDF_EXTENSIONS, PERL_EXTENSIONS, PHP_EXTENSIONS, POWERPOINT_EXTENSIONS, POWERSHELL_EXTENSIONS, PUG_EXTENSIONS, PYTHON_EXTENSIONS, R_EXTENSIONS, RTF_EXTENSIONS, RUBY_EXTENSIONS, RUST_EXTENSIONS, SCALA_EXTENSIONS, SCHEME_EXTENSIONS, SCSS_EXTENSIONS, SHELL_EXTENSIONS, SOURCE_CODE_EXTENSIONS, SQL_EXTENSIONS, STYLUS_EXTENSIONS, SVELTE_EXTENSIONS, SWIFT_EXTENSIONS, TEXT_EXTENSIONS, TYPESCRIPT_EXTENSIONS, V_EXTENSIONS, VIDEO_EXTENSIONS, VUE_EXTENSIONS, WORD_EXTENSIONS, XML_EXTENSIONS, YAML_EXTENSIONS, ZIG_EXTENSIONS, } from "./fileTypes.js";
29
+ export { ARCHIVE_MIME_TYPES, AUDIO_MIME_TYPES, DATA_MIME_TYPES, DOCUMENT_MIME_TYPES, EXTENSION_MIME_MAP, getMimeTypeForExtension, IMAGE_MIME_TYPES, MIME_TYPES, SOURCE_CODE_MIME_TYPES, TEXT_MIME_TYPES, VIDEO_MIME_TYPES, } from "./mimeConstants.js";
30
+ export { ADA_EXTENSIONS, AI_VISION_EXTENSIONS, ARCHIVE_EXTENSIONS, ASSEMBLY_EXTENSIONS, AUDIO_EXTENSIONS, C_EXTENSIONS, CLOJURE_EXTENSIONS, COBOL_EXTENSIONS, CONFIG_EXTENSIONS, CPP_EXTENSIONS, CRYSTAL_EXTENSIONS, CSHARP_EXTENSIONS, CSS_EXTENSIONS, CSV_EXTENSIONS, D_EXTENSIONS, DART_EXTENSIONS, DATA_EXTENSIONS, DATABASE_EXTENSIONS, DESIGN_EXTENSIONS, DOCKERFILE_EXTENSIONS, DOCUMENT_EXTENSIONS, EJS_EXTENSIONS, ELIXIR_EXTENSIONS, ERLANG_EXTENSIONS, EXCEL_EXTENSIONS, EXECUTABLE_EXTENSIONS, FILE_EXTENSIONS, FORTRAN_EXTENSIONS, FSHARP_EXTENSIONS, GO_EXTENSIONS, GROOVY_EXTENSIONS, HANDLEBARS_EXTENSIONS, HASKELL_EXTENSIONS, HTML_EXTENSIONS, IMAGE_EXTENSIONS, JAVA_EXTENSIONS, JAVASCRIPT_EXTENSIONS, JSON_EXTENSIONS, JULIA_EXTENSIONS, KOTLIN_EXTENSIONS, LESS_EXTENSIONS, LISP_EXTENSIONS, LUA_EXTENSIONS, MAKEFILE_EXTENSIONS, MARKDOWN_EXTENSIONS, NIM_EXTENSIONS, OBJECTIVE_C_EXTENSIONS, OCAML_EXTENSIONS, OPENDOCUMENT_EXTENSIONS, PASCAL_EXTENSIONS, PDF_EXTENSIONS, PERL_EXTENSIONS, PHP_EXTENSIONS, POWERPOINT_EXTENSIONS, POWERSHELL_EXTENSIONS, PUG_EXTENSIONS, PYTHON_EXTENSIONS, R_EXTENSIONS, RTF_EXTENSIONS, RUBY_EXTENSIONS, RUST_EXTENSIONS, SCALA_EXTENSIONS, SCHEME_EXTENSIONS, SCSS_EXTENSIONS, SHELL_EXTENSIONS, SOURCE_CODE_EXTENSIONS, SQL_EXTENSIONS, STYLUS_EXTENSIONS, SVELTE_EXTENSIONS, SWIFT_EXTENSIONS, TEXT_EXTENSIONS, TYPESCRIPT_EXTENSIONS, V_EXTENSIONS, VIDEO_EXTENSIONS, VUE_EXTENSIONS, WORD_EXTENSIONS, XML_EXTENSIONS, YAML_EXTENSIONS, ZIG_EXTENSIONS, } from "./fileExtensions.js";
31
31
  export { detectLanguageFromFilename, EXACT_FILENAME_MAP, getLanguageIdentifier, getSupportedExtensions, getSupportedFilenames, isSourceCodeFile, LANGUAGE_MAP, } from "./languageMap.js";
32
32
  export { ARCHIVE_LIMITS, bytesToMB, formatBytes, getSizeLimitForType, isWithinSizeLimit, mbToBytes, PROCESSING_LIMITS, SIZE_LIMITS, SIZE_LIMITS_BYTES, SIZE_LIMITS_MB, validateFileSize, YAML_LIMITS, } from "./sizeLimits.js";
@@ -36,7 +36,7 @@ EXTENSION_MIME_MAP, getMimeTypeForExtension,
36
36
  IMAGE_MIME_TYPES,
37
37
  // Types
38
38
  // Combined MIME types
39
- MIME_TYPES, SOURCE_CODE_MIME_TYPES, TEXT_MIME_TYPES, VIDEO_MIME_TYPES, } from "./mimeTypes.js";
39
+ MIME_TYPES, SOURCE_CODE_MIME_TYPES, TEXT_MIME_TYPES, VIDEO_MIME_TYPES, } from "./mimeConstants.js";
40
40
  // =============================================================================
41
41
  // FILE EXTENSIONS
42
42
  // =============================================================================
@@ -66,7 +66,7 @@ JSON_EXTENSIONS, JULIA_EXTENSIONS, KOTLIN_EXTENSIONS, LESS_EXTENSIONS, LISP_EXTE
66
66
  // Text extensions
67
67
  TEXT_EXTENSIONS, TYPESCRIPT_EXTENSIONS, V_EXTENSIONS,
68
68
  // Multimedia extensions
69
- VIDEO_EXTENSIONS, VUE_EXTENSIONS, WORD_EXTENSIONS, XML_EXTENSIONS, YAML_EXTENSIONS, ZIG_EXTENSIONS, } from "./fileTypes.js";
69
+ VIDEO_EXTENSIONS, VUE_EXTENSIONS, WORD_EXTENSIONS, XML_EXTENSIONS, YAML_EXTENSIONS, ZIG_EXTENSIONS, } from "./fileExtensions.js";
70
70
  // =============================================================================
71
71
  // LANGUAGE DETECTION
72
72
  // =============================================================================
@@ -122,3 +122,11 @@ export { getProcessorForFile, getSupportedFileTypes, isFileTypeSupported, proces
122
122
  // CLI HELPERS
123
123
  // =============================================================================
124
124
  export { detectMimeType, fileExists, getCliUsage, getFileExtension, getSupportedFileTypes as getCliSupportedFileTypes, listSupportedFileTypes, loadFileFromPath, processFileFromPath, } from "./cli/index.js";
125
+ // =============================================================================
126
+ // STANDALONE SAFETY UTILITIES (extracted from the former I/O processor system)
127
+ // =============================================================================
128
+ // PII detection, response validation, and tripwire evaluation are now
129
+ // standalone utilities in src/lib/utils/ and wired directly into
130
+ // generate() and stream() via native options (piiDetection, responseValidation,
131
+ // inputValidation). See src/lib/utils/piiDetector.ts, responseValidator.ts,
132
+ // and tripwireEvaluator.ts.
@@ -10,7 +10,7 @@ import { composeAbortSignals, createTimeoutController, TimeoutError, } from "../
10
10
  import { withTimeout } from "../utils/async/index.js";
11
11
  import { estimateTokens } from "../utils/tokenEstimation.js";
12
12
  import { transformToolExecutions } from "../utils/transformationUtils.js";
13
- import { buildGeminiResponseSchema, buildNativeConfig, buildNativeToolDeclarations, collectStreamChunks, collectStreamChunksIncremental, computeMaxSteps, createTextChannel, buildUserPartsWithMultimodal, executeNativeToolCalls, extractTextFromParts, extractThoughtSignature, handleMaxStepsTermination, prependConversationMessages, pushModelResponseToHistory, } from "./googleNativeGemini3.js";
13
+ import { buildGeminiResponseSchema, buildNativeConfig, buildNativeToolDeclarations, collectStreamChunks, collectStreamChunksIncremental, computeMaxSteps, createTextChannel, buildUserPartsWithMultimodal, executeNativeToolCalls, extractTextFromParts, extractThoughtSignature, handleMaxStepsTermination, prependConversationMessages, pushModelResponseToHistory, DedupExecuteMap, } from "./googleNativeGemini3.js";
14
14
  import { createProxyFetch } from "../proxy/proxyFetch.js";
15
15
  // Google AI Live API types now imported from ../types/providerSpecific.js
16
16
  // Import proper types for multimodal message handling
@@ -521,7 +521,7 @@ export class GoogleAIStudioProvider extends BaseProvider {
521
521
  });
522
522
  // Convert tools
523
523
  let toolsConfig;
524
- let executeMap = new Map();
524
+ let executeMap = new DedupExecuteMap();
525
525
  let originalNameMap = new Map();
526
526
  if (options.tools &&
527
527
  Object.keys(options.tools).length > 0 &&
@@ -808,7 +808,7 @@ export class GoogleAIStudioProvider extends BaseProvider {
808
808
  });
809
809
  // Convert tools (a0269210: trust options.tools — already merged + filtered upstream)
810
810
  let toolsConfig;
811
- let executeMap = new Map();
811
+ let executeMap = new DedupExecuteMap();
812
812
  let originalNameMap = new Map();
813
813
  const shouldUseTools = !options.disableTools;
814
814
  if (shouldUseTools) {
@@ -10,6 +10,24 @@
10
10
  */
11
11
  import type { GenerateStopReason, ThinkingConfig, ChatMessage, CollectedChunkResult, MinimalChatMessage, NativeFunctionCall, NativeFunctionResponse, NativeToolDeclarationsResult, NativeToolsConfig, TextChannel, VertexNativePart, GeminiMultimodalInput } from "../types/index.js";
12
12
  import type { Tool } from "../types/index.js";
13
+ /**
14
+ * A per-turn tool execute map that deduplicates identical tool calls.
15
+ *
16
+ * Gemini occasionally re-emits a tool call with identical arguments across
17
+ * agentic steps even though the prior result is already in the conversation
18
+ * history (BZ-3327). Re-executing produces duplicate side effects and
19
+ * duplicate reports for the user, plus wasted tokens. This map caches the
20
+ * result of each {tool name + args} executed within the turn and returns it
21
+ * for any identical re-request instead of running the tool again.
22
+ *
23
+ * Providers build a fresh executeMap per request, so the cache scope is
24
+ * exactly one turn. Only `.get()` is overridden (the sole access path used by
25
+ * the native agentic loops), so iteration still yields the raw executors.
26
+ */
27
+ export declare class DedupExecuteMap extends Map<string, Tool["execute"]> {
28
+ private readonly resultCache;
29
+ get(name: string): Tool["execute"] | undefined;
30
+ }
13
31
  export declare function sanitizeForGoogleFunctionName(name: string): string;
14
32
  /**
15
33
  * Resolve a sanitized Gemini tool name to one that is both unique within
@@ -17,6 +17,52 @@ import { convertZodToJsonSchema, ensureNestedSchemaTypes, inlineJsonSchema, isZo
17
17
  import { createNativeThinkingConfig } from "../utils/thinkingConfig.js";
18
18
  import { jsonSchema as aiJsonSchema, tool as createAISDKTool, } from "../utils/tool.js";
19
19
  // ── Functions ──
20
+ /** Stable, key-order-independent serialization of tool args for the dedup key. */
21
+ function stableStringifyForDedup(value) {
22
+ return JSON.stringify(value, (_key, val) => val && typeof val === "object" && !Array.isArray(val)
23
+ ? Object.keys(val)
24
+ .sort()
25
+ .reduce((acc, key) => {
26
+ acc[key] = val[key];
27
+ return acc;
28
+ }, {})
29
+ : val);
30
+ }
31
+ /**
32
+ * A per-turn tool execute map that deduplicates identical tool calls.
33
+ *
34
+ * Gemini occasionally re-emits a tool call with identical arguments across
35
+ * agentic steps even though the prior result is already in the conversation
36
+ * history (BZ-3327). Re-executing produces duplicate side effects and
37
+ * duplicate reports for the user, plus wasted tokens. This map caches the
38
+ * result of each {tool name + args} executed within the turn and returns it
39
+ * for any identical re-request instead of running the tool again.
40
+ *
41
+ * Providers build a fresh executeMap per request, so the cache scope is
42
+ * exactly one turn. Only `.get()` is overridden (the sole access path used by
43
+ * the native agentic loops), so iteration still yields the raw executors.
44
+ */
45
+ export class DedupExecuteMap extends Map {
46
+ resultCache = new Map();
47
+ get(name) {
48
+ const execute = super.get(name);
49
+ if (!execute) {
50
+ return execute;
51
+ }
52
+ const resultCache = this.resultCache;
53
+ const wrapped = async (args, options) => {
54
+ const key = `${name}::${stableStringifyForDedup(args)}`;
55
+ if (resultCache.has(key)) {
56
+ logger.warn(`[DedupExecuteMap] Tool "${name}" re-requested with identical arguments in the same turn — reusing the previous result instead of re-executing.`);
57
+ return resultCache.get(key);
58
+ }
59
+ const result = await execute(args, options);
60
+ resultCache.set(key, result);
61
+ return result;
62
+ };
63
+ return wrapped;
64
+ }
65
+ }
20
66
  /**
21
67
  * Google's `function_declarations[].name` validator regex.
22
68
  *
@@ -323,7 +369,7 @@ export function normalizeToolsForJsonSchemaProvider(tools) {
323
369
  */
324
370
  export function buildNativeToolDeclarations(tools) {
325
371
  const functionDeclarations = [];
326
- const executeMap = new Map();
372
+ const executeMap = new DedupExecuteMap();
327
373
  const skippedTools = [];
328
374
  const renamedTools = [];
329
375
  // Disambiguate distinct originals that collapse onto the same sanitized
@@ -24,7 +24,7 @@ import { convertZodToJsonSchema, inlineJsonSchema, ensureNestedSchemaTypes, } fr
24
24
  import { createNativeThinkingConfig } from "../utils/thinkingConfig.js";
25
25
  import { TimeoutError, raceWithAbort, withTimeout, } from "../utils/async/index.js";
26
26
  import { parseTimeout } from "../utils/timeout.js";
27
- import { appendStepText, buildAbortedTurnMessage, buildContextCapMessage, buildToolLoopCapMessage, buildTurnStalledMessage, buildTurnTimeoutMessage, buildWrapupNudgeText, createContextGuard, createTextChannel, createTurnClock, extractThoughtSignature, isAbortError, mapGeminiFinishReason, prependConversationMessages, resolveTurnStopReason, } from "./googleNativeGemini3.js";
27
+ import { appendStepText, buildAbortedTurnMessage, buildContextCapMessage, buildToolLoopCapMessage, buildTurnStalledMessage, buildTurnTimeoutMessage, buildWrapupNudgeText, createContextGuard, createTextChannel, createTurnClock, extractThoughtSignature, isAbortError, mapGeminiFinishReason, prependConversationMessages, resolveTurnStopReason, DedupExecuteMap, } from "./googleNativeGemini3.js";
28
28
  import { getContextWindowSize } from "../constants/contextWindows.js";
29
29
  import { ATTR, LANGFUSE_ATTR, spanJsonAttribute, tracers, withClientSpan, withClientStreamSpan, withSpan, } from "../telemetry/index.js";
30
30
  import { SpanKind, SpanStatusCode, context as otelContext, trace as otelTrace, } from "@opentelemetry/api";
@@ -1138,7 +1138,7 @@ export class GoogleVertexProvider extends BaseProvider {
1138
1138
  });
1139
1139
  // Convert Vercel AI SDK tools to @google/genai FunctionDeclarations
1140
1140
  let tools;
1141
- const executeMap = new Map();
1141
+ const executeMap = new DedupExecuteMap();
1142
1142
  if (options.tools &&
1143
1143
  Object.keys(options.tools).length > 0 &&
1144
1144
  !options.disableTools) {
@@ -2085,7 +2085,7 @@ export class GoogleVertexProvider extends BaseProvider {
2085
2085
  const combinedTools = !options.disableTools ? options.tools || {} : {};
2086
2086
  // Convert Vercel AI SDK tools to @google/genai FunctionDeclarations
2087
2087
  let tools;
2088
- const executeMap = new Map();
2088
+ const executeMap = new DedupExecuteMap();
2089
2089
  if (Object.keys(combinedTools).length > 0) {
2090
2090
  const functionDeclarations = [];
2091
2091
  for (const [name, tool] of Object.entries(combinedTools)) {
@@ -3116,7 +3116,7 @@ export class GoogleVertexProvider extends BaseProvider {
3116
3116
  : userContentParts);
3117
3117
  // Convert tools to Anthropic format if present
3118
3118
  let tools;
3119
- const executeMap = new Map();
3119
+ const executeMap = new DedupExecuteMap();
3120
3120
  if (options.tools &&
3121
3121
  Object.keys(options.tools).length > 0 &&
3122
3122
  !options.disableTools) {
@@ -4425,7 +4425,7 @@ export class GoogleVertexProvider extends BaseProvider {
4425
4425
  : userContentParts);
4426
4426
  // Convert tools to Anthropic format if present
4427
4427
  let tools;
4428
- const executeMap = new Map();
4428
+ const executeMap = new DedupExecuteMap();
4429
4429
  const toolExecutions = [];
4430
4430
  // Defensive guard: Vertex generate() bypasses BaseProvider.generate(), so
4431
4431
  // disableTools must be checked here before native tool declarations are