Skip to content

feat(core): comprehensive multimodal architecture with modular refact… - #253

Merged
murdore merged 1 commit into
releasefrom
feat/all-multi-modality
Dec 1, 2025
Merged

murdore merged 1 commit into
releasefrom
feat/all-multi-modality

Conversation

@murdore

@murdore murdore commented Nov 27, 2025 •

Copy link
Copy Markdown
Contributor

…oring and enhanced testing

Architecture Refactoring (54% reduction in BaseProvider):

  • Extract BaseProvider into 6 SRP-compliant modules (GenerationHandler, MessageBuilder, StreamHandler, TelemetryHandler, ToolsManager, Utilities)
  • Refactor 11 providers to use composition over inheritance
  • Reduce BaseProvider from 2,418 to 1,118 lines

Multimodal Enhancements:

  • Add 53 new vision models (GPT-5, Claude 4.x, Llama 4, Gemini 2.0, DeepSeek R1)
  • Add AudioContent and VideoContent types with comprehensive JSDoc
  • Implement type guards for enhanced type safety
  • Expand support across Bedrock, LiteLLM, Mistral, Ollama providers
  • Add Claude 4.5 Haiku (claude-haiku-4-5-20251001) model support

Ollama Critical Fixes:

  • Fix streaming failures (0 chunks → 100% pass rate)
  • Add intelligent tool management (auto-disable for non-capable models)
  • Add OpenAI-compatible streaming mode support
  • Fix message field handling (options.prompt vs options.messages)
  • Add tool capability detection for 8 models

Documentation (5,479 new lines):

  • Add CLAUDE.md: Complete architecture guide for AI-assisted development
  • Add HAYSTACK_MULTIMODAL_ANALYSIS.md: Comparative analysis (748 lines)
  • Add MULTIMODALITY_GAP_ANALYSIS.md: Capability gap analysis (2,165 lines)
  • Add MULTIMODAL_IMPLEMENTATION_GUIDE.md: Implementation roadmap (2,184 lines)
  • Add provider compatibility matrix (11 providers × 19 features)
  • Document SDK stream tool discovery bug fix

Test Infrastructure:

  • Add sequential test runner with rate limit protection
  • Add smoke test scripts for rapid provider validation
  • Add comprehensive testing documentation (TESTING_SCRIPTS.md)
  • Fix stream chunk handling for 62 MCP tools
  • Add case-insensitive test validation

Code Quality:

  • Fix max-params violation (7→4 via ToolUtilities interface)
  • Fix max-depth violation in ollama.ts (7→6 via optional chaining)
  • Fix pre-commit hook npm test command
  • Add type guards for stream chunk processing
  • Clean up direct tools and MCP server code

Pull Request

Description

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🧹 Code refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧪 Test coverage improvement
  • 🔧 Build/CI configuration change

Related Issues

  • Fixes #
  • Related to #

Changes Made

AI Provider Impact

  • OpenAI
  • Anthropic
  • Google AI/Vertex
  • AWS Bedrock
  • Azure OpenAI
  • Hugging Face
  • Ollama
  • Mistral
  • All providers
  • No provider-specific changes

Component Impact

  • CLI
  • SDK
  • MCP Integration
  • Streaming
  • Tool Calling
  • Configuration
  • Documentation
  • Tests

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • E2E tests added/updated
  • Manual testing performed
  • All existing tests pass

Test Environment

  • OS:
  • Node.js version:
  • Package manager:

Performance Impact

  • No performance impact
  • Performance improvement
  • Minor performance impact (acceptable)
  • Significant performance impact (needs discussion)

Breaking Changes

Screenshots/Demo

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Additional Notes

Summary by CodeRabbit

  • New Features

    • Claude 4.5 Haiku model added; Ollama OpenAI-compatible mode; expanded multimodal support (unified multimodal types, audio streaming, PDF→image conversion); broader vision-capable model coverage and provider alias (google-ai-studio).
  • Bug Fixes

    • Improved SDK stream test reliability; fixed Ollama non-stream message handling; removed deprecated searchFiles tool and removed ENABLE_STREAMING/ENABLE_FALLBACK docs entries.
  • Documentation

    • Added multimodal guides, gap analyses, provider compatibility matrix, testing scripts, and PR/post‑merge analysis reports.
  • Refactor

    • Internal provider core modularization and centralized message-building/streaming flow.

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI review requested due to automatic review settings November 27, 2025 07:25
@coderabbitai

coderabbitai Bot commented Nov 27, 2025 •

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Refactors BaseProvider into composition modules (MessageBuilder, StreamHandler, GenerationHandler, TelemetryHandler, ToolsManager, Utilities), centralizes multimodal types, adds Claude 4.5 Haiku model and token entries, introduces PDF→image conversion, adds Ollama OpenAI-compatible mode, updates many providers to use unified message-building, adjusts tooling/MCP behavior, adds dependencies and test tooling, and expands documentation.

Changes

Cohort / File(s) Summary
Documentation & Guides
CLAUDE.md, HAYSTACK_MULTIMODAL_ANALYSIS.md, MULTIMODALITY_GAP_ANALYSIS.md, MULTIMODAL_IMPLEMENTATION_GUIDE.md, README.md, docs/getting-started/API-REFERENCE.md, docs/getting-started/provider-setup.md, docs/reference/provider-feature-compatibility.md, docs/sdk/api-reference.md, test/TESTING_SCRIPTS.md, COMMIT_ANALYSIS_REPORT.md, OLLAMA_FIX_SUMMARY.md, OLLAMA_TEST_VERIFICATION.md, PR_COMMENTS_IMPACT_ANALYSIS.md, PR_COMMENTS_SOLUTION_PLAN.md, PR_REVIEW_FIXES_SUMMARY.md
Added extensive design/implementation docs, analyses, guides, and test/run documentation; removed or updated documented feature flags (ENABLE_STREAMING, ENABLE_FALLBACK) and added README link for provider compatibility.
Core composition modules & BaseProvider
src/lib/core/baseProvider.ts, src/lib/core/modules/MessageBuilder.ts, src/lib/core/modules/StreamHandler.ts, src/lib/core/modules/GenerationHandler.ts, src/lib/core/modules/TelemetryHandler.ts, src/lib/core/modules/ToolsManager.ts, src/lib/core/modules/Utilities.ts, src/lib/core/constants.ts, src/lib/core/modelConfiguration.ts
Reworked BaseProvider to delegate to new modules for message construction, streaming, generation, telemetry, tool management, and utilities; adjusted provider max-token defaults and added Ollama toolCapableModels config.
Multimodal types & type reorganization
src/lib/types/multimodal.ts, src/lib/types/content.ts, src/lib/types/conversation.ts, src/lib/types/index.ts, src/lib/types/streamTypes.ts, src/lib/types/generateTypes.ts
Introduced centralized multimodal.ts with content types and type guards; re-exported types for compatibility; updated stream/generate types to use unified Content[]; added streaming audio types.
Provider updates — unified message-building
src/lib/providers/... (anthropic.ts, azureOpenai.ts, googleAiStudio.ts, googleVertex.ts, huggingFace.ts, openAI.ts, openaiCompatible.ts, mistral.ts, amazonBedrock.ts, litellm.ts, ollama.ts)
Consolidated message construction by delegating to BaseProvider's buildMessagesForStream; Bedrock now sanitizes filenames and handles multimodal messages; LiteLLM added streaming/tools integration; Ollama added OpenAI-compatible mode and adjusted timeouts/tool gating.
Tools / MCP / Agent changes
src/lib/agent/directTools.ts, src/lib/mcp/servers/agent/directToolsServer.ts, src/lib/neurolink.ts, src/lib/factories/providerRegistry.ts
Removed searchFiles tool and its public mappings; changed tool-category mapping fallback for searchFiles; NeuroLink: increased external proxy timeout, auto-disable MCP tools for non-tool-capable Ollama models, and add tool-aware system prompts for MCP streams; added google-ai-studio alias.
Model registry, enums, tokens
src/lib/models/modelRegistry.ts, src/lib/constants/enums.ts, src/lib/constants/tokens.ts
Added Claude 4.5 Haiku model entry and enum member; added token-limit entries for the new model (duplicate registry insertion noted).
Utilities & processors
src/lib/utils/pdfProcessor.ts, src/lib/utils/messageBuilder.ts, src/lib/utils/imageProcessor.ts, src/lib/adapters/providerImageAdapter.ts
Added pdfjs-dist + canvas usage and convertPDFToImages for PDF→images; updated message-builder/provider adapter imports to multimodal types; expanded vision-capable model lists and clarified provider-specific PDF/CSV guidance.
Tests & scripts
test/continuous-test-suite.ts, test/run-all-providers-sequential.sh, test/test-all-providers.sh, test-stream-debug.ts
Tests refactored to use a shared NeuroLink SDK instance, updated test signatures and parsing, increased chunk allowances, added sequential/multi-provider runner scripts and debug helper.
Dependencies & build
package.json, scripts/env-validation.cjs
Added canvas and pdfjs-dist dependencies and updated pnpm.onlyBuiltDependencies; env-validation improved parsing and messaging.
CLI
src/cli/factories/commandFactory.ts
Added google-ai-studio to CLI provider choices.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User
    participant BaseProvider
    participant MessageBuilder
    participant ToolsManager
    participant GenerationHandler
    participant StreamHandler
    participant TelemetryHandler

    User->>BaseProvider: generate/stream(options)
    BaseProvider->>MessageBuilder: buildMessagesForStream(options)
    MessageBuilder-->>BaseProvider: CoreMessage[]
    BaseProvider->>ToolsManager: getAllTools()
    ToolsManager-->>BaseProvider: tools map
    alt streaming
        BaseProvider->>StreamHandler: validateStreamOptions(options)
        StreamHandler-->>BaseProvider: stream generator
        BaseProvider->>TelemetryHandler: createStreamTelemetryConfig(...)
    else generation
        BaseProvider->>GenerationHandler: executeGeneration(model, messages, tools, options)
        GenerationHandler->>ToolsManager: persist/extract tool calls (onStepFinish)
        GenerationHandler-->>BaseProvider: EnhancedGenerateResult
    end
    BaseProvider->>TelemetryHandler: recordPerformanceMetrics(result, duration)
    TelemetryHandler-->>BaseProvider: analytics/evaluation
    BaseProvider-->>User: return stream/generate result
Loading
sequenceDiagram
    autonumber
    participant NeuroLink
    participant OllamaProvider
    participant ModelConfig
    participant ToolsManager

    OllamaProvider->>ModelConfig: load toolCapableModels
    ModelConfig-->>OllamaProvider: list
    OllamaProvider->>NeuroLink: if model not tool-capable -> set disableTools
    OllamaProvider->>ToolsManager: getAllTools() (if enabled)
    OllamaProvider->>OllamaProvider: isOpenAICompatibleMode()?
    alt OpenAI-compatible
        OllamaProvider->>OllamaProvider: POST /v1/chat/completions (stream)
        OllamaProvider->>OllamaProvider: parseOpenAIStreamResponse -> emit chunks
    else Native
        OllamaProvider->>OllamaProvider: POST /api/generate (native)
        OllamaProvider->>OllamaProvider: parse native stream -> emit chunks
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

  • Areas needing extra attention:
    • src/lib/core/baseProvider.ts and all new modules: verify behavioral parity, error paths, and dependency injection.
    • MessageBuilder / StreamHandler / GenerationHandler / TelemetryHandler / ToolsManager / Utilities: contracts, async error handling, and lazy imports.
    • src/lib/providers/ollama.ts: dual-mode routing, OpenAI-compatible stream parsing, and tool-capable gating.
    • src/lib/utils/pdfProcessor.ts: pdfjs + canvas rendering, resource cleanup, and platform dependencies.
    • src/lib/models/modelRegistry.ts: duplicate Claude 4.5 Haiku insertion and token/pricing consistency.
    • Tests: shared NeuroLink SDK lifecycle, isolation, and increased chunk/time tolerances.

Possibly related PRs

Suggested labels

released

Poem

🐰 Hop, hop — new modules in a row,

Messages stitch multimodal flow.
PDFs turn into picture light,
Ollama chats both day and night.
Claude hums haiku, nimble and bright.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main refactoring effort (comprehensive multimodal architecture with modular refactoring), which is the central theme of this large PR.
Docstring Coverage ✅ Passed Docstring coverage is 86.36% which is sufficient. The required threshold is 80.00%.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Nov 27, 2025 •

Copy link
Copy Markdown
Contributor

✅ Single Commit Policy - COMPLIANT

Status: Policy requirements met • 1 commit • Valid format • Ready for merge

📊 View validation details

📝 Commit Details

  • Hash: 50bba698a2a37c2ff7c00ca3516c3e78674cb03d
  • Message: feat(core): comprehensive multimodal architecture with modular refactoring and enhanced testing
  • Author: Sachin Sharma

✅ Validation Results

  • Single commit requirement met
  • No merge commits in branch
  • Semantic commit message format verified
  • Ready for squash merge to release branch

🤖 Automated validation by NeuroLink Single Commit Enforcement

@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a comprehensive multimodal architecture refactoring with significant code reduction and enhanced functionality. The main changes include extracting BaseProvider into 6 modular components (54% code reduction from 2,418 to 1,118 lines), adding extensive multimodal support for audio/video content, fixing critical Ollama streaming issues, and introducing robust testing infrastructure.

Key Changes

  • Architecture: Refactored BaseProvider using composition over inheritance with 6 SRP-compliant modules (MessageBuilder, StreamHandler, GenerationHandler, TelemetryHandler, Utilities, ToolsManager)
  • Multimodal Support: Added AudioContent and VideoContent types with comprehensive JSDoc, type guards, and expanded provider support
  • Ollama Fixes: Fixed streaming failures, added intelligent tool management, OpenAI-compatible mode, and tool capability detection
  • Testing: Introduced sequential test runner with rate limit protection, shared SDK instance pattern, and improved test validation

Reviewed changes

Copilot reviewed 53 out of 54 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/lib/core/baseProvider.ts Major refactoring to use composition pattern with 6 dedicated modules, reducing complexity
src/lib/core/modules/*.ts New modular architecture components (MessageBuilder, StreamHandler, GenerationHandler, etc.)
src/lib/types/multimodal.ts Comprehensive multimodal type system with AudioContent, VideoContent, and type guards
src/lib/providers/*.ts Updated 11 providers to use buildMessagesForStream helper, eliminating code duplication
src/lib/providers/ollama.ts Fixed streaming issues, added OpenAI compatibility mode, intelligent tool management
test/continuous-test-suite.ts Refactored SDK tests to use shared instance pattern, improved chunk handling, case-insensitive validation
test/run-all-providers-sequential.sh New sequential test runner with rate limit protection and logging
src/lib/utils/pdfProcessor.ts Added PDF to image conversion with canvas support, updated Mistral PDF config
package.json Added canvas (3.2.0) and pdfjs-dist (5.4.296) dependencies
src/lib/constants/enums.ts Added Claude 4.5 Haiku model enum
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

Comment thread src/lib/core/modules/Utilities.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lib/providers/ollama.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/continuous-test-suite.ts (1)

2757-2779: Based on my verification, the review comment is accurate and well-founded. I've confirmed:

  1. testCLIStreamCSVAndScreenshot is a streaming test: It calls the CLI with the "stream" command at line 2198, making a streaming API call.

  2. The skip logic excludes it: The shouldSkipStreamingTest function checks testName.toLowerCase().includes("stream") && !testName.toLowerCase().includes("screenshot"). Since the test name contains "screenshot", the condition evaluates to false, and the test is NOT skipped.

  3. It will hit the same restriction: When provider=openai and model is gpt-5* or o3*, this test will attempt to use the streaming endpoint and encounter the organization verification requirement—the exact same restriction that causes other streaming tests (like "SDK Stream", "CLI Stream") to be skipped.

  4. Inconsistency exists: The skip logic explicitly treats streaming tests with "screenshot" differently, but they still use streaming endpoints and face the same org-verification barrier, creating potential flakiness.


Streaming tests with "screenshot" excluded from skip logic still hit org-verification restrictions

shouldSkipStreamingTest skips most *Stream* tests for OpenAI gpt-5/o3 models, but explicitly excludes tests with "screenshot" in their name. The testCLIStreamCSVAndScreenshot test uses the streaming endpoint (line 2198) and will hit the same organization-verification barrier, causing flakiness when provider=openai and model is gpt-5* or o3*.

Either extend the skip logic to include screenshot streaming tests, or document why they're safe to run under these model restrictions.

🧹 Nitpick comments (21)
src/lib/utils/messageBuilder.ts (1)

629-636: CSV file detection logic may miss Buffer inputs.

The hasCSVFiles check only detects string file paths ending with .csv. It doesn't account for:

  1. CSV files passed as Buffer in options.input.csvFiles
  2. Buffer files in options.input.files that are CSVs

Consider simplifying to also check the csvFiles array length:

   const hasCSVFiles =
     (options.input.csvFiles && options.input.csvFiles.length > 0) ||
     (options.input.files &&
-      options.input.files.some((f) =>
-        typeof f === "string" ? f.toLowerCase().endsWith(".csv") : false,
-      ));
+      options.input.files.some((f) => {
+        if (typeof f === "string") {
+          return f.toLowerCase().endsWith(".csv");
+        }
+        // Buffer files in the files array could be CSVs, but we can't detect without processing
+        // The csvFiles array is the canonical source for explicit CSV buffers
+        return false;
+      }));

Alternatively, since options.input.csvFiles is already checked first, the current logic works correctly for explicit CSV file arrays - the string path check is just an additional heuristic for the generic files array.

test/test-all-providers.sh (1)

1-33: Suggest adding build validation and provider configuration checks.

The script provides useful smoke testing functionality, but could be more robust with a few additions:

  1. Build validation: Add a check that dist/cli/index.js exists before running tests
  2. Provider configuration validation: Consider checking for required API keys/config per provider before attempting tests (e.g., OPENAI_API_KEY for openai)
  3. Executable permissions: Ensure the script is marked as executable in git

Consider adding these checks at the beginning:

 #!/bin/bash
+
+# Validate build exists
+if [ ! -f "dist/cli/index.js" ]; then
+    echo "❌ Error: dist/cli/index.js not found. Run 'pnpm run build:cli' first."
+    exit 1
+fi
 
 # Quick test script to check all providers
 PROVIDERS=("openai" "anthropic" "vertex" "google-ai-studio" "bedrock" "ollama")

Additionally, consider documenting the prerequisite of running pnpm run build:cli in the script's header comments.

src/lib/providers/anthropic.ts (1)

195-206: Consider cleanup: Empty tool tracking arrays.

Lines 195-206 initialize empty toolCalls and toolResults arrays that are never populated before being returned in the StreamResult. Since tool execution is handled via the onStepFinish callback (lines 173-185), these empty arrays may be vestigial.

If these arrays are not used by consumers, consider removing them:

-      const toolCalls: Array<{
-        toolCallId: string;
-        toolName: string;
-        args: Record<string, unknown>;
-      }> = [];
-
-      const toolResults: Array<{
-        toolName: string;
-        status: "success" | "failure";
-        output?: JsonValue;
-        id: string;
-      }> = [];
-
       return {
         stream: transformedStream,
         provider: this.providerName,
         model: this.modelName,
-        toolCalls,
-        toolResults,
         // Note: omit usage/finishReason to avoid blocking streaming; compute asynchronously if needed.
       };
test/TESTING_SCRIPTS.md (1)

426-426: Verify the "Last Updated" date.

Line 426 shows "November 2, 2025" as the last update date. If the current date is November 27, 2025 (as indicated in the system date), this date appears to be from the past. Consider updating to the actual last modification date or removing the date field if it's not being actively maintained.

package.json (1)

182-182: Native dependency canvas may require build tools on user systems.

The canvas package requires native compilation (Python, C++ build tools). This could cause installation failures for users without these prerequisites. Consider:

  1. Documenting the build requirements in README
  2. Making this an optional dependency if PDF-to-image is not a core feature
CLAUDE.md (1)

176-200: Update MessageBuilder path reference to reflect new modular structure.

The documentation references src/lib/utils/messageBuilder.ts as the central component for message construction. However, this PR introduces src/lib/core/modules/MessageBuilder.ts as the new centralized message builder class. Consider updating the documentation to reflect both files and their distinct roles:

  • src/lib/core/modules/MessageBuilder.ts - Class-based message builder used by providers
  • src/lib/utils/messageBuilder.ts - Utility functions for message array construction
test/run-all-providers-sequential.sh (1)

63-63: Remove unused PROVIDER_START variable.

The variable is assigned but never used, as flagged by static analysis.

   LOG_FILE="$LOG_DIR/test-$provider.log"
-  PROVIDER_START=$(date +%s)
 
   # Run test and capture output
src/lib/providers/amazonBedrock.ts (1)

875-894: Filename sanitization may not fully comply with Bedrock requirements.

The current sanitization removes only the file extension, but Bedrock's document name restrictions allow only "alphanumeric, whitespace, hyphens, parentheses, brackets". Filenames with other special characters (dots in multi-extension names, underscores, etc.) could still cause issues.

             // Extract basename and sanitize for Bedrock's filename requirements
             // Bedrock only allows: alphanumeric, whitespace, hyphens, parentheses, brackets
             // NOTE: Periods (.) are NOT allowed, so we remove the extension
             let filename =
               typeof contentItem.name === "string" && contentItem.name
                 ? path.basename(contentItem.name)
                 : "document-pdf";

             // Remove file extension (periods not allowed by Bedrock)
-            filename = filename.replace(/\.[^.]+$/, "");
+            filename = filename
+              .replace(/\.[^.]+$/, "")  // Remove last extension
+              .replace(/[^a-zA-Z0-9\s\-\(\)\[\]]/g, "-");  // Replace invalid chars with hyphen
src/lib/core/modules/MessageBuilder.ts (1)

42-117: Significant code duplication between buildMessages and buildMessagesForStream.

Both methods contain nearly identical implementations:

  1. hasMultimodalInput() helper defined inline twice (lines 43-51 and 131-141)
  2. Multimodal options construction duplicated
  3. CoreMessage conversion logic duplicated (lines 97-116 and 187-206)

Consider extracting shared logic into private methods:

+  /**
+   * Check if options contain multimodal input
+   */
+  private hasMultimodalInput(opts: StreamOptions | TextGenerationOptions): boolean {
+    const input = opts.input as MultimodalInput | undefined;
+    return !!(
+      input?.images?.length ||
+      input?.content?.length ||
+      input?.csvFiles?.length ||
+      input?.pdfFiles?.length ||
+      input?.files?.length
+    );
+  }
+
+  /**
+   * Convert internal messages to CoreMessage format
+   */
+  private convertToCoreMessages(messages: Array<{ role: string; content: unknown }>): CoreMessage[] {
+    return messages.map((msg) => {
+      if (typeof msg.content === "string") {
+        return {
+          role: msg.role as "user" | "assistant" | "system",
+          content: msg.content,
+        } as CoreMessage;
+      } else {
+        return {
+          role: msg.role as "user" | "assistant" | "system",
+          content: (msg.content as Array<{ type: string; text?: string; image?: unknown }>).map((item) => {
+            if (item.type === "text") {
+              return { type: "text", text: item.text || "" };
+            } else if (item.type === "image") {
+              return { type: "image", image: item.image || "" };
+            }
+            return item;
+          }),
+        } as CoreMessage;
+      }
+    });
+  }

Also applies to: 127-207

MULTIMODAL_IMPLEMENTATION_GUIDE.md (1)

1403-1529: Align TTS provider/auth strategy and type locations with existing decisions

The TTS section proposes a separate TTSProcessor with its own per‑provider selection and cloud SDK dependencies, and earlier sections talk about centralizing multimodal types into src/lib/types/multimodal.ts. In the repo, TTS for the google-ai provider is already planned to reuse GOOGLE_AI_API_KEY and the existing google-ai auth path rather than a distinct TTS auth surface, and multimodal types are being consolidated into a shared module. To avoid drift between this guide and the actual implementation, consider explicitly calling out:

  • That Google TTS flows should reuse the existing google-ai provider auth (GOOGLE_AI_API_KEY), not introduce a parallel key, and
  • That any new MultimodalInput/content types referenced here must live in the centralized multimodal types module rather than being (re)defined in providers or core.

This keeps the guide in sync with the current phased refactor and naming/auth decisions.

Also applies to: 315-445

src/lib/neurolink.ts (3)

718-747: Note operational impact of increasing external server default timeout to 30s

Bumping defaultTimeout for ExternalServerManager from 15s to 30s will make slow or hung external MCP servers take longer to be classified as failed, which is likely needed for proxied setups (LiteLLM, etc.) but does increase worst‑case wait times for callers relying on those tools. It’s worth double‑checking that:

  • This timeout aligns with any upstream proxy/ingress timeouts, and
  • Call sites invoking external MCP tools still have their own application‑level timeouts or fallbacks so a single slow server doesn’t stall end‑user flows longer than desired.

2752-2782: Ollama auto tool‑disable logic looks good; consider clarifying matching semantics

The Ollama branch in stream() mirrors the generate() logic and will correctly auto‑disable tools when the active model is not listed in toolCapableModels, which should significantly reduce pointless tool prompting on non‑tooling models.

Two small points to consider:

  • Matching is options.model?.toLowerCase().includes(capableModel.toLowerCase()); if toolCapableModels ever contain very short or generic substrings, this might match unintended variants. If you expect exact tags (e.g. llama3.2), a stricter equality or suffix match might be safer.
  • When options.model is unset, we silently disable tools because modelSupportsTools stays false. If the intent is “no model specified → default to a known tool‑capable model,” you might instead prefer to skip this block when options.model is undefined and rely on the provider default.

If you’re happy with current behavior, no change is strictly required.


2980-3008: Stream path tool‑aware system prompt mirrors generate; watch discovery cost

Using getAllAvailableTools() and createToolAwareSystemPrompt() inside createMCPStream brings the streaming path in line with the MCP generate path, which is good for consistency and observability (the debug logging of prompt length is also useful).

Given getAllAvailableTools() already has caching and short‑circuits to an empty list on failure, this should be acceptable, but it does mean:

  • First stream in a process may incur the full discovery cost before the cache warms.
  • Subsequent streams within NEUROLINK_TOOL_CACHE_DURATION will be cheap.

If you notice startup latency for the first stream, you might consider warming the tool cache as part of MCP initialization or constructor‑time diagnostics, but it’s not strictly necessary.

src/lib/core/modules/StreamHandler.ts (1)

32-75: StreamHandler abstraction looks good; minor tweaks for override safety and future audio support

This module nicely centralizes stream validation, result shaping, and analytics; the reuse of validateStreamOpts and createAnalytics should simplify providers.

Two small refinements to consider:

  • In createStreamResult, additionalProps can currently override provider, model, or even stream because it’s spread last:

    return {
      stream,
      provider: this.providerName,
      model: this.modelName,
      ...additionalProps,
    };

    If you don’t intend callers to override those core fields, flip the order so fixed metadata always wins:

  • return {

  • stream,

  • provider: this.providerName,

  • model: this.modelName,

  • ...additionalProps,

  • };

  • return {
  • ...additionalProps,
  • stream,
  • provider: this.providerName,
  • model: this.modelName,
  • };

- `validateStreamOptionsOnly` currently enforces `input.text` or `input.images` and will reject purely audio‑based streams. If you plan to route real‑time audio streaming through the same `StreamOptions` shape in the future, you may want to extend this check to also accept `input.audio` when present, or document that this validator is only for text/image streaming paths.

If the current usage is strictly text/image, these are optional adjustments rather than blockers.  



Also applies to: 80-104, 108-154

</blockquote></details>
<details>
<summary>src/lib/core/baseProvider.ts (1)</summary><blockquote>

`256-268`: **Unnecessary rejection and error handling in streaming delay.**

The timeout delay for fake streaming has an unusual pattern: it rejects if `timeoutId` is falsy (which won't happen with `setTimeout`), and the `.catch()` handler logs but swallows the error silently. This creates dead code and an awkward control flow.



Consider simplifying to a straightforward delay:

```diff
-                    await new Promise((resolve, reject) => {
-                      const timeoutId = setTimeout(
-                        resolve,
-                        Math.random() * 9 + 1,
-                      );
-                      // Handle potential timeout issues
-                      if (!timeoutId) {
-                        reject(new Error("Failed to create timeout"));
-                      }
-                    }).catch((err) => {
-                      logger.error("Error in streaming delay:", err);
-                    });
+                    await new Promise((resolve) =>
+                      setTimeout(resolve, Math.random() * 9 + 1)
+                    );
docs/reference/provider-feature-compatibility.md (1)

455-455: Minor style: "CLI interface" is redundant.

"CLI" already stands for "Command Line Interface," so "CLI interface" is tautological. Consider using just "CLI" or "command line interface."

-18. CLI Business Tools - Custom tools via CLI interface
+18. CLI Business Tools - Custom tools via CLI
test/continuous-test-suite.ts (1)

1938-1942: SDK CSV test accepts 18250 as “calculation correct” even though it doesn’t match the fixture math

In testSDKGenerateCSV the numeric check treats 18250 as an acceptable “calculation correct” value alongside 4500, 10000, 2250, and 16750, but those are the only values implied by the inventory.csv contents.

If the intention is to assert correct arithmetic, it would be safer to restrict this list to values that are actually derivable from the fixture, and treat 18250 as a failure (or move it behind a separate “approximate/alternative” path).

src/lib/providers/ollama.ts (1)

491-573: OpenAI streaming usage accounting never infers promptTokens when API omits usage

In parseOpenAIStreamResponse, totalPromptTokens is initialized to 0 and never updated; when the API doesn’t send data.usage, the final finish chunk reports promptTokens: 0 even though you already have access to the full message history (and at least a rough estimateTokens helper).

This only affects analytics/usage accounting, not correctness, but you may want to:

  • Accept the lack of usage and clearly document that promptTokens are unknown in OpenAI-compatible streaming mode; or
  • Derive a best-effort promptTokens value from the original messages (e.g., via estimateTokens(JSON.stringify(messages)), passed into this helper).
src/lib/core/modules/ToolsManager.ts (1)

51-55: Stored toolExecutor is never used

setupToolExecutor saves sdk.executeTool into this.toolExecutor, but all execution paths in this module call the underlying toolInfo.execute (for custom tools) or neurolink.executeExternalMCPTool (for external MCP tools). toolExecutor is never read.

If there’s no planned use for toolExecutor, consider removing it from the class state and from setupToolExecutor to avoid confusion about which execution path is authoritative. If you do intend to execute via the SDK’s executeTool, you may want to route custom tool execution through that instead of calling toolInfo.execute directly.

Also applies to: 82-102

src/lib/core/modules/Utilities.ts (1)

228-250: String timeouts without units fall back to defaultTimeout

getTimeout treats "30s", "2m", "1h" as expected, but a plain numeric string like "5000" doesn’t match any suffix branch and silently falls back to defaultTimeout.

If you expect callers might provide "5000" or "2500" as strings, you could special-case numeric-only strings:

-    const timeoutStr = options.timeout.toLowerCase();
-    const value = parseInt(timeoutStr);
+    const timeoutStr = options.timeout.toLowerCase();
+    const value = parseInt(timeoutStr, 10);
+
+    if (!Number.isNaN(value) && !/[hms]/.test(timeoutStr)) {
+      return value;
+    }

Otherwise, consider documenting that string timeouts must include a unit suffix.

src/lib/core/modules/GenerationHandler.ts (1)

281-289: Fix string concatenation for undefined text.

When result.text is undefined, the optional chaining returns undefined, and concatenation produces "undefined..." in logs.

     logger.debug("NeuroLink Raw AI Response Analysis", {
       provider: this.providerName,
       model: this.modelName,
       responseTextLength: (result.text as string)?.length || 0,
-      responsePreview: (result.text as string)?.substring(0, 500) + "...",
+      responsePreview: (result.text as string)?.substring(0, 500) ?? "(no text)",
       finishReason: result.finishReason,
       usage: result.usage,
     });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63b3e43 and 3eb6739.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (53)
  • CLAUDE.md (1 hunks)
  • HAYSTACK_MULTIMODAL_ANALYSIS.md (1 hunks)
  • MULTIMODALITY_GAP_ANALYSIS.md (1 hunks)
  • MULTIMODAL_IMPLEMENTATION_GUIDE.md (1 hunks)
  • README.md (1 hunks)
  • SDK_STREAM_BUG_FIX_SUMMARY.md (1 hunks)
  • docs/getting-started/API-REFERENCE.md (0 hunks)
  • docs/getting-started/provider-setup.md (0 hunks)
  • docs/reference/provider-feature-compatibility.md (1 hunks)
  • docs/sdk/api-reference.md (0 hunks)
  • package.json (3 hunks)
  • scripts/env-validation.cjs (21 hunks)
  • src/cli/factories/commandFactory.ts (1 hunks)
  • src/lib/adapters/providerImageAdapter.ts (6 hunks)
  • src/lib/agent/directTools.ts (1 hunks)
  • src/lib/constants/enums.ts (1 hunks)
  • src/lib/constants/tokens.ts (3 hunks)
  • src/lib/core/baseProvider.ts (10 hunks)
  • src/lib/core/constants.ts (2 hunks)
  • src/lib/core/modelConfiguration.ts (1 hunks)
  • src/lib/core/modules/GenerationHandler.ts (1 hunks)
  • src/lib/core/modules/MessageBuilder.ts (1 hunks)
  • src/lib/core/modules/StreamHandler.ts (1 hunks)
  • src/lib/core/modules/TelemetryHandler.ts (1 hunks)
  • src/lib/core/modules/ToolsManager.ts (1 hunks)
  • src/lib/core/modules/Utilities.ts (1 hunks)
  • src/lib/factories/providerRegistry.ts (1 hunks)
  • src/lib/mcp/servers/agent/directToolsServer.ts (0 hunks)
  • src/lib/models/modelRegistry.ts (1 hunks)
  • src/lib/neurolink.ts (4 hunks)
  • src/lib/providers/amazonBedrock.ts (3 hunks)
  • src/lib/providers/anthropic.ts (1 hunks)
  • src/lib/providers/azureOpenai.ts (1 hunks)
  • src/lib/providers/googleAiStudio.ts (1 hunks)
  • src/lib/providers/googleVertex.ts (1 hunks)
  • src/lib/providers/huggingFace.ts (1 hunks)
  • src/lib/providers/litellm.ts (5 hunks)
  • src/lib/providers/mistral.ts (2 hunks)
  • src/lib/providers/ollama.ts (8 hunks)
  • src/lib/providers/openAI.ts (1 hunks)
  • src/lib/providers/openaiCompatible.ts (1 hunks)
  • src/lib/types/content.ts (1 hunks)
  • src/lib/types/conversation.ts (1 hunks)
  • src/lib/types/index.ts (1 hunks)
  • src/lib/types/multimodal.ts (1 hunks)
  • src/lib/types/streamTypes.ts (1 hunks)
  • src/lib/utils/imageProcessor.ts (1 hunks)
  • src/lib/utils/messageBuilder.ts (4 hunks)
  • src/lib/utils/pdfProcessor.ts (4 hunks)
  • test/TESTING_SCRIPTS.md (1 hunks)
  • test/continuous-test-suite.ts (10 hunks)
  • test/run-all-providers-sequential.sh (1 hunks)
  • test/test-all-providers.sh (1 hunks)
💤 Files with no reviewable changes (4)
  • docs/sdk/api-reference.md
  • docs/getting-started/API-REFERENCE.md
  • docs/getting-started/provider-setup.md
  • src/lib/mcp/servers/agent/directToolsServer.ts
🧰 Additional context used
🧠 Learnings (13)
📚 Learning: 2025-09-17T17:55:15.261Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 173
File: src/lib/index.ts:16-16
Timestamp: 2025-09-17T17:55:15.261Z
Learning: In src/lib/types/providers.ts, ProviderConfig was renamed to AIModelProviderConfig to deduplicate type names, as there was an existing ProviderConfig type that better suited the "ProviderConfig" name. This was an intentional breaking change for better type organization.

Applied to files:

  • src/lib/providers/mistral.ts
  • src/lib/core/modelConfiguration.ts
  • src/lib/providers/huggingFace.ts
  • src/lib/providers/googleAiStudio.ts
  • src/lib/providers/azureOpenai.ts
  • src/lib/providers/googleVertex.ts
  • README.md
  • src/lib/core/modules/MessageBuilder.ts
  • src/lib/providers/ollama.ts
  • src/lib/providers/openAI.ts
  • src/lib/types/conversation.ts
  • src/lib/factories/providerRegistry.ts
  • src/lib/utils/imageProcessor.ts
  • MULTIMODAL_IMPLEMENTATION_GUIDE.md
  • src/lib/core/constants.ts
  • docs/reference/provider-feature-compatibility.md
  • src/lib/adapters/providerImageAdapter.ts
  • src/cli/factories/commandFactory.ts
  • src/lib/core/baseProvider.ts
  • src/lib/providers/openaiCompatible.ts
  • src/lib/models/modelRegistry.ts
  • src/lib/core/modules/ToolsManager.ts
  • src/lib/core/modules/TelemetryHandler.ts
  • src/lib/types/multimodal.ts
  • src/lib/constants/tokens.ts
  • src/lib/types/index.ts
  • src/lib/providers/anthropic.ts
  • src/lib/providers/litellm.ts
  • src/lib/core/modules/Utilities.ts
  • src/lib/types/content.ts
  • src/lib/core/modules/GenerationHandler.ts
📚 Learning: 2025-09-17T18:14:34.960Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 173
File: src/lib/types/index.ts:58-62
Timestamp: 2025-09-17T18:14:34.960Z
Learning: RajuSudhar explained that in the Neurolink codebase, there are multiple ProviderConfig types causing inconsistency. One existing ProviderConfig type better suited the "ProviderConfig" name, so they renamed the less-suitable one to AIModelProviderConfig to free up the name. Adding backward compatibility aliases would worsen naming inconsistency rather than help. The remaining duplicates will be systematically deduplicated in the 07-Types-Module.md TODO as part of their phased refactor approach.

Applied to files:

  • src/lib/providers/huggingFace.ts
  • src/lib/providers/azureOpenai.ts
  • src/lib/providers/openAI.ts
  • CLAUDE.md
  • src/lib/factories/providerRegistry.ts
  • MULTIMODAL_IMPLEMENTATION_GUIDE.md
  • docs/reference/provider-feature-compatibility.md
  • src/lib/adapters/providerImageAdapter.ts
  • src/lib/providers/openaiCompatible.ts
  • MULTIMODALITY_GAP_ANALYSIS.md
📚 Learning: 2025-09-01T22:58:39.149Z
Learnt from: sudharsan-juspay
Repo: juspay/neurolink PR: 140
File: src/lib/core/types.ts:198-203
Timestamp: 2025-09-01T22:58:39.149Z
Learning: In src/lib/core/types.ts, StreamOptions (imported from streamTypes.js) and StreamingOptions are intentionally different types with different use cases. StreamingOptions is for unified AI requests with multiple provider configurations, while StreamOptions is for individual streaming operations.

Applied to files:

  • src/lib/providers/huggingFace.ts
  • src/lib/providers/googleAiStudio.ts
  • src/lib/providers/googleVertex.ts
  • src/lib/neurolink.ts
  • src/lib/core/modules/StreamHandler.ts
  • src/lib/providers/openaiCompatible.ts
  • src/lib/types/streamTypes.ts
  • src/lib/providers/litellm.ts
  • src/lib/utils/messageBuilder.ts
📚 Learning: 2025-09-02T13:50:42.770Z
Learnt from: YasmeenOgo
Repo: juspay/neurolink PR: 145
File: src/lib/core/types.ts:0-0
Timestamp: 2025-09-02T13:50:42.770Z
Learning: The APIVersions enum in src/lib/core/types.ts now contains comprehensive API version constants for all major AI providers: Azure OpenAI (latest, stable, legacy), OpenAI (current, beta), Google AI (current, beta), and Anthropic (current). This centralization helps avoid API version drift across the codebase.

Applied to files:

  • src/lib/providers/googleAiStudio.ts
  • src/lib/constants/enums.ts
  • src/lib/providers/azureOpenai.ts
  • README.md
  • src/lib/providers/ollama.ts
  • src/lib/providers/openAI.ts
  • src/lib/factories/providerRegistry.ts
  • src/lib/core/constants.ts
  • src/lib/models/modelRegistry.ts
  • src/lib/types/index.ts
  • src/lib/providers/anthropic.ts
  • src/lib/providers/litellm.ts
📚 Learning: 2025-09-28T21:00:08.243Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 174
File: src/lib/mcp/contracts/mcpContract.ts:0-0
Timestamp: 2025-09-28T21:00:08.243Z
Learning: The src/lib/mcp/contracts/mcpContract.ts file was completely removed during the MCP types refactor in PR #174, with its types moved to centralized modules like src/lib/types/mcpTypes.ts and src/lib/types/index.ts.

Applied to files:

  • src/lib/types/conversation.ts
  • src/lib/types/content.ts
📚 Learning: 2025-11-04T22:14:18.719Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-11-04T22:14:18.719Z
Learning: In the juspay/neurolink repository, all new type definitions must be placed in src/lib/types/. New type definitions outside this directory should be flagged and blocked in code reviews.

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-09-01T14:12:14.227Z
Learnt from: swaroopvarma1
Repo: juspay/neurolink PR: 141
File: docs/REAL-TIME-SPEECH-AGENTS.md:124-149
Timestamp: 2025-09-01T14:12:14.227Z
Learning: In the NeuroLink Speech-to-Speech agent system, the team prefers simple void-returning APIs (sendAudioFrame, sendText, flush) over Promise-based backpressure mechanisms, prioritizing ease of use and implementation simplicity for real-time speech processing.

Applied to files:

  • MULTIMODAL_IMPLEMENTATION_GUIDE.md
📚 Learning: 2025-11-17T13:53:20.209Z
Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 237
File: memory-bank/tts-provider-implementation-plan.md:92-106
Timestamp: 2025-11-17T13:53:20.209Z
Learning: In PR 237's TTS modality implementation approach, TTS functionality uses GOOGLE_AI_API_KEY (not GOOGLE_TTS_API_KEY) when using the google-ai provider. TTS is implemented as an output modality that leverages the existing google-ai provider authentication.

Applied to files:

  • MULTIMODAL_IMPLEMENTATION_GUIDE.md
📚 Learning: 2025-09-24T06:42:06.088Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 185
File: src/lib/evaluation/contextBuilder.ts:79-85
Timestamp: 2025-09-24T06:42:06.088Z
Learning: In the NeuroLink codebase, using `(options.prompt || [])` pattern for handling potentially undefined prompt arrays is the preferred approach over extracting to a normalized variable when building conversation history in the ContextBuilder class.

Applied to files:

  • src/lib/providers/amazonBedrock.ts
  • src/lib/neurolink.ts
  • src/lib/utils/messageBuilder.ts
📚 Learning: 2025-09-07T09:14:50.565Z
Learnt from: Yaswanth-2874
Repo: juspay/neurolink PR: 149
File: test/conversation-memory-test.js:66-69
Timestamp: 2025-09-07T09:14:50.565Z
Learning: In the juspay/neurolink repository, test files don't need defensive type guards for known API contracts. The user prefers to keep test code simpler without additional safety checks when the data structure is guaranteed.

Applied to files:

  • test/continuous-test-suite.ts
📚 Learning: 2025-09-10T08:22:11.910Z
Learnt from: sudharsan-juspay
Repo: juspay/neurolink PR: 160
File: src/lib/providers/index.ts:43-44
Timestamp: 2025-09-10T08:22:11.910Z
Learning: In the Neurolink project, type deduplication across modules (like ProviderName definitions) should be handled as separate tasks rather than mixed with other refactoring efforts, as there are multiple such occurrences throughout the codebase that need systematic cleanup.

Applied to files:

  • MULTIMODALITY_GAP_ANALYSIS.md
📚 Learning: 2025-11-05T20:31:04.103Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 227
File: src/lib/utils/redis.ts:15-15
Timestamp: 2025-11-05T20:31:04.103Z
Learning: In the juspay/neurolink repository, type centralization rules (requiring types in src/lib/types/) do not apply to private, non-exported utility types used within a single file. Simple readability helpers like `type RedisClient = ReturnType<typeof createClient>` should remain in their implementation file when they are not exported and only used locally. Only exported types shared across modules, business/domain types, and public API types require centralization.

Applied to files:

  • src/lib/types/index.ts
  • src/lib/types/content.ts
📚 Learning: 2025-09-01T06:15:59.759Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 133
File: src/lib/core/types.ts:208-210
Timestamp: 2025-09-01T06:15:59.759Z
Learning: The middleware?: MiddlewareFactoryOptions field is already present in both TextGenerationOptions and StreamOptions interfaces in the neurolink codebase.

Applied to files:

  • src/lib/utils/messageBuilder.ts
🧬 Code graph analysis (9)
src/lib/providers/mistral.ts (1)
src/lib/utils/providerConfig.ts (1)
  • getProviderModel (178-180)
test/test-all-providers.sh (3)
src/lib/core/baseProvider.ts (1)
  • generate (465-506)
src/lib/neurolink.ts (1)
  • generate (1649-1901)
src/lib/providers/amazonBedrock.ts (1)
  • generate (164-250)
src/lib/core/modules/MessageBuilder.ts (5)
src/lib/types/index.ts (2)
  • AIProviderName (9-9)
  • StreamOptions (181-181)
src/lib/types/content.ts (1)
  • MultimodalInput (27-27)
src/lib/types/multimodal.ts (1)
  • MultimodalInput (209-222)
src/lib/utils/messageBuilder.ts (1)
  • buildMultimodalMessagesArray (436-728)
src/lib/types/streamTypes.ts (1)
  • StreamOptions (156-233)
src/lib/providers/ollama.ts (2)
src/lib/utils/multimodalOptionsBuilder.ts (1)
  • buildMultimodalOptions (45-70)
src/lib/utils/messageBuilder.ts (1)
  • buildMultimodalMessagesArray (436-728)
src/lib/providers/amazonBedrock.ts (4)
src/lib/types/streamTypes.ts (1)
  • StreamOptions (156-233)
src/lib/utils/multimodalOptionsBuilder.ts (1)
  • buildMultimodalOptions (45-70)
src/lib/utils/messageBuilder.ts (1)
  • buildMultimodalMessagesArray (436-728)
src/lib/types/providers.ts (1)
  • BedrockMessage (482-485)
src/lib/models/modelRegistry.ts (2)
src/lib/types/index.ts (1)
  • AIProviderName (9-9)
src/lib/index.ts (1)
  • AIProviderName (38-38)
src/lib/types/multimodal.ts (2)
src/lib/types/content.ts (20)
  • TextContent (20-20)
  • ImageContent (21-21)
  • CSVContent (22-22)
  • PDFContent (23-23)
  • AudioContent (24-24)
  • VideoContent (25-25)
  • Content (26-26)
  • MultimodalInput (27-27)
  • MultimodalMessage (28-28)
  • VisionCapability (29-29)
  • ProviderImageFormat (30-30)
  • ProcessedImage (31-31)
  • ProviderMultimodalPayload (32-32)
  • isTextContent (34-34)
  • isImageContent (35-35)
  • isCSVContent (36-36)
  • isPDFContent (37-37)
  • isAudioContent (38-38)
  • isVideoContent (39-39)
  • isMultimodalInput (40-40)
src/lib/types/conversation.ts (2)
  • MessageContent (128-128)
  • MultimodalChatMessage (128-128)
src/lib/providers/litellm.ts (2)
src/lib/types/streamTypes.ts (1)
  • StreamResult (239-280)
src/lib/core/constants.ts (1)
  • DEFAULT_MAX_STEPS (10-10)
src/lib/core/modules/GenerationHandler.ts (5)
src/lib/types/index.ts (3)
  • AIProviderName (9-9)
  • StandardRecord (16-16)
  • UnknownRecord (50-50)
src/lib/core/baseProvider.ts (1)
  • generateText (522-560)
src/lib/neurolink.ts (1)
  • generateText (1907-1923)
src/lib/types/tools.ts (1)
  • ToolCallObject (221-228)
src/lib/types/providers.ts (2)
  • AISDKGenerateResult (410-420)
  • ExtendedTool (405-405)
🪛 LanguageTool
HAYSTACK_MULTIMODAL_ANALYSIS.md

[grammar] ~687-~687: Ensure spelling is correct
Context: ...** (cost/privacy flexibility) ### What NeuroLink Does Better 1. **Vision model integrat...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

MULTIMODAL_IMPLEMENTATION_GUIDE.md

[style] ~117-~117: Consider a different adjective to strengthen your wording.
Context: ...## Current Architecture Problems After deep analysis of the actual codebase impleme...

(DEEP_PROFOUND)


[style] ~172-~172: To elevate your writing, try using a synonym here.
Context: ...enance burden, difficult to understand, hard to extend ### Solution Architecture #...

(HARD_TO)


[uncategorized] ~1076-~1076: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...Pattern: Upload → Transcribe → Store as markdown with header Dependencies to Add: ...

(MARKDOWN_NNP)


[style] ~2034-~2034: Consider using a different verb for a more formal wording.
Context: ...lease Preparation - [ ] Run linter and fix issues: npm run lint - [ ] Run type c...

(FIX_RESOLVE)

docs/reference/provider-feature-compatibility.md

[style] ~455-~455: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: .... CLI Business Tools - Custom tools via CLI interface #### Enterprise Features Tests (1 test...

(ACRONYM_TAUTOLOGY)

MULTIMODALITY_GAP_ANALYSIS.md

[style] ~40-~40: Consider a different adjective to strengthen your wording.
Context: ...aintainability and extensibility After deep analysis of the actual codebase, **crit...

(DEEP_PROFOUND)


[style] ~719-~719: This adverb was used twice in the sentence. Consider removing one of them or replacing them with a synonym.
Context: ... - ❌ Only PCM streaming - ❌ Gemini Live only (no other providers) - ❌ No audio file ...

(ADVERB_REPETITION_PREMIUM)


[uncategorized] ~770-~770: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...xing After transcription: 1. Store as markdown document 2. Summarize by LLM 3. Chunk f...

(MARKDOWN_NNP)

🪛 Shellcheck (0.11.0)
test/run-all-providers-sequential.sh

[warning] 63-63: PROVIDER_START appears unused. Verify use (or export if used externally).

(SC2034)

Comment thread memory-bank/HAYSTACK_MULTIMODAL_ANALYSIS.md
Comment thread MULTIMODALITY_GAP_ANALYSIS.md Outdated
Comment thread SDK_STREAM_BUG_FIX_SUMMARY.md Outdated
Comment on lines +102 to +105
// Claude 4.5 Series (Latest - October 2025)
CLAUDE_4_5_HAIKU = "claude-haiku-4-5-20251001",

// Claude 3.5 Series

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Search for any references to claude-haiku-4-5 variants in the codebase
rg "claude-haiku-4-5" -n

Repository: juspay/neurolink

Length of output: 720


🏁 Script executed:

# Search for tokens document mentioned in the summary
fd -type f -name "*token*" | head -20

Repository: juspay/neurolink

Length of output: 230


🌐 Web query:

Claude 4.5 Haiku model ID Anthropic official documentation

💡 Result:

Official Anthropic model ID: claude-haiku-4-5 (alias/endpoint: claude-haiku-4-5 / full messages API id anthropic:messages:claude-haiku-4-5-20251001). [1][2]

Sources:
[1] Anthropic — Claude Haiku 4.5 (official product page).
[2] Promptfoo / Anthropic provider docs listing message-model IDs.


Rewrite the review comment to correctly identify that tokens.ts (not enums.ts) contains the incorrect model ID.

The official Claude 4.5 Haiku model ID from Anthropic is claude-haiku-4-5-20251001. While enums.ts correctly uses this ID, src/lib/constants/tokens.ts (lines 83, 124, 137) incorrectly references claude-haiku-4-5-20251015, which appears to be an outdated variant. The tokens document must be updated to use the official model ID claude-haiku-4-5-20251001 to maintain consistency across the codebase and ensure proper token counting against the correct model.

🤖 Prompt for AI Agents
In src/lib/constants/tokens.ts around lines 83, 124 and 137 the model ID is
incorrectly set to "claude-haiku-4-5-20251015"; update those occurrences to the
official Anthropic ID "claude-haiku-4-5-20251001" to match enums.ts, ensuring
all token mappings reference the correct model; after updating, run any
token-related tests or linters and verify there are no remaining references to
the outdated ID.

Comment thread src/lib/constants/tokens.ts Outdated
Comment on lines +206 to +258
/**
* Handle tool execution storage if available
*/
async handleToolExecutionStorage(
toolCalls: unknown[],
toolResults: unknown[],
options: TextGenerationOptions | StreamOptions,
currentTime: Date,
): Promise<void> {
// Check if tools are not empty
const hasToolData =
(toolCalls && toolCalls.length > 0) ||
(toolResults && toolResults.length > 0);

// Check if NeuroLink instance is available and has tool execution storage
const hasStorageAvailable =
this.neurolink?.isToolExecutionStorageAvailable();

// Early return if storage is not available or no tool data
if (!hasStorageAvailable || !hasToolData || !this.neurolink) {
return;
}

const sessionId =
(options.context?.sessionId as string) ||
(options as unknown as { sessionId?: string }).sessionId ||
`session-${nanoid()}`;
const userId =
(options.context?.userId as string) ||
(options as unknown as { userId?: string }).userId;

try {
await this.neurolink.storeToolExecutions(
sessionId,
userId,
toolCalls as Array<{
toolCallId?: string;
toolName?: string;
args?: Record<string, unknown>;
[key: string]: unknown;
}>,
toolResults as Array<{
toolCallId?: string;
toolName?: string;
result?: unknown;
[key: string]: unknown;
}>,
currentTime,
);
} catch (error) {
logger.warn("Failed to store tool executions:", error);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Duplicate handleToolExecutionStorage implementation exists in BaseProvider.

This method appears to be duplicated from BaseProvider (lines 968-1022 in baseProvider.ts). The BaseProvider version should delegate to TelemetryHandler to avoid duplication, or this version should be removed if BaseProvider's implementation is the authoritative one.

Additionally, the toolResults type assertion (lines 247-252) is missing the error field that exists in the BaseProvider version:

         toolResults as Array<{
           toolCallId?: string;
           toolName?: string;
           result?: unknown;
+          error?: string;
           [key: string]: unknown;
         }>,
🤖 Prompt for AI Agents
In src/lib/core/modules/TelemetryHandler.ts around lines 206 to 258, this method
duplicates BaseProvider's handleToolExecutionStorage (baseProvider.ts lines
~968-1022) and also omits the `error` field in the toolResults type assertion;
remove this duplicate or change BaseProvider to delegate to TelemetryHandler
(keep single authoritative implementation), and if keeping this file update the
toolResults type to include error?: unknown (match BaseProvider), ensure
delegation/removal preserves behavior and type compatibility for
sessionId/userId handling and the neurolink.storeToolExecutions call.

Comment thread src/lib/models/modelRegistry.ts
Comment thread src/lib/providers/litellm.ts
Comment thread src/lib/types/multimodal.ts
Comment thread test/run-all-providers-sequential.sh Outdated
murdore added a commit that referenced this pull request Nov 27, 2025
… review

Critical Fixes (4):
1. Fix Ollama provider message extraction bug (src/lib/providers/ollama.ts:186-191)
   - Was checking options.prompt first, causing failures in non-stream mode
   - Now correctly checks options.messages first, then falls back to options.prompt

2. Fix Claude 4.5 Haiku model ID mismatch (3 locations)
   - src/lib/constants/tokens.ts:83 - ANTHROPIC_MODELS["claude-haiku-4.5"]
   - src/lib/constants/tokens.ts:124 - EXTENDED_MODEL_LIMITS["claude-haiku-4.5"]
   - src/lib/constants/tokens.ts:137 - BEDROCK_MODELS["anthropic.claude-haiku-4.5"]
   - Changed from "claude-haiku-4-5-20251015" to "claude-haiku-4-5-20251001"
   - Changed Bedrock from "anthropic.claude-haiku-4-5-20251015-v1:0" to "...20251001..."

3. Fix Claude 4.5 Haiku pricing and limits (src/lib/models/modelRegistry.ts:220-221, 231)
   - Corrected input cost: $0.0008 → $0.001 per 1K tokens
   - Corrected output cost: $0.004 → $0.005 per 1K tokens
   - Corrected max output tokens: 8,192 → 64,000

4. Fix MultimodalInput type narrowness (src/lib/types/multimodal.ts:212)
   - Changed content type from Array<TextContent | ImageContent> to Content[]
   - Now accepts full Content union (Text, Image, PDF, CSV, Audio, Video)
   - Also fixed in generateTypes.ts and streamTypes.ts
   - Removed unused TextContent/ImageContent imports

Major Fixes (2):
5. Fix data loss with falsy tool results (src/lib/core/modules/GenerationHandler.ts:213)
   - Changed || to ?? operator to preserve falsy values (0, false, "")

6. Fix inconsistent text extraction (src/lib/core/modules/MessageBuilder.ts:154-157)
   - Added fallback chain: prompt → input?.text → ""

Minor Fixes (6):
7. Enhanced type safety (src/lib/core/modules/Utilities.ts:378-383)
   - Added Date and RegExp instance checks for middleware options validation

8-11. Documentation fixes:
   - HAYSTACK_MULTIMODAL_ANALYSIS.md:58 - Fixed malformed table separator
   - MULTIMODALITY_GAP_ANALYSIS.md:10 - Replaced local path with generic URL
   - SDK_STREAM_BUG_FIX_SUMMARY.md:4 - Fixed date (October → November 27)
   - test/run-all-providers-sequential.sh:13 - Fixed provider count (12 → 11)

Impact:
- Ollama provider now works correctly in non-stream mode
- Claude 4.5 Haiku uses correct model ID across all providers (Anthropic, Bedrock, Vertex)
- Pricing and token limits are accurate for Claude 4.5 Haiku
- Multimodal inputs now accept all content types (not just text and images)
- Tool results with falsy values are preserved correctly
- Type safety improved across the codebase

Files Changed: 13
- 7 source files (providers, constants, types, core modules)
- 4 documentation files
- 1 test script
- 7 new analysis documents added
@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

Copilot AI review requested due to automatic review settings November 27, 2025 19:29
@murdore
murdore force-pushed the feat/all-multi-modality branch from ee86229 to 07e1b37 Compare November 27, 2025 19:29
@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 61 out of 62 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

// 2. The middleware property must be an object with configuration.
if (
typeof middlewareOpts !== "object" ||
middlewareOpts === null ||

Copilot AI Nov 27, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable 'middlewareOpts' is of type date, object or regular expression, but it is compared to an expression of type null.

Copilot uses AI. Check for mistakes.
@murdore

murdore commented Nov 27, 2025

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Nov 27, 2025

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/lib/providers/openaiCompatible.ts (1)

230-297: Add missing await to streamText call in executeStream—this will cause runtime failure without it

In executeStream (line 236), streamText is called without await:

const result = streamText({
  model,
  messages: messages,
  // ...
});

The ai SDK's streamText returns a Promise that resolves to an object with a textStream property. Without await, result is a Promise, not the resolved result object. This causes:

  • Line 261: for await (const chunk of result.textStream) fails because result.textStream is undefined
  • Line 274: Analytics receives a Promise instead of the result object
  • Runtime error: Cannot iterate undefined

This pattern is inconsistent with all other providers in the codebase (anthropic.ts, openAI.ts, mistral.ts, litellm.ts, huggingFace.ts, azureOpenai.ts, googleAiStudio.ts), which all use await streamText().

Add await:

-      const result = streamText({
+      const result = await streamText({
         model,
         messages: messages,
         ...(options.maxTokens !== null && options.maxTokens !== undefined
           ? { maxTokens: options.maxTokens }
           : {}),
         ...(options.temperature !== null && options.temperature !== undefined
           ? { temperature: options.temperature }
           : {}),
         maxSteps: options.maxSteps || DEFAULT_MAX_STEPS,
         tools: options.tools,
         toolChoice: "auto",
         abortSignal: timeoutController?.controller.signal,
         onStepFinish: ({ toolCalls, toolResults }) => {
           this.handleToolExecutionStorage(
             toolCalls,
             toolResults,
             options,
             new Date(),
           ).catch((error: unknown) => {
             logger.warn(
               "[OpenAiCompatibleProvider] Failed to store tool executions",
               {
                 provider: this.providerName,
                 error: error instanceof Error ? error.message : String(error),
               },
             );
           });
         },
       });
src/lib/neurolink.ts (1)

2980-3008: Tool-aware streaming prompt should probably respect disableTools (especially with Ollama auto-disable).

createMCPStream always calls getAllAvailableTools() and createToolAwareSystemPrompt, then passes the enhanced prompt into provider.stream(), even when options.disableTools has been set to true (including by the new Ollama gating).

That means smaller Ollama models still see a large tool menu in the system prompt while the actual tool path is disabled, which is contrary to the “prevent overwhelming smaller models with massive tool descriptions” intent and adds avoidable overhead.

Consider short‑circuiting when tools are disabled:

-    const availableTools = await this.getAllAvailableTools();
-    const enhancedSystemPrompt = this.createToolAwareSystemPrompt(
-      options.systemPrompt,
-      availableTools,
-    );
+    let enhancedSystemPrompt = options.systemPrompt || "";
+    let availableTools = [];
+    if (!options.disableTools) {
+      availableTools = await this.getAllAvailableTools();
+      enhancedSystemPrompt = this.createToolAwareSystemPrompt(
+        options.systemPrompt,
+        availableTools,
+      );
+    }
@@
-    const streamResult = await provider.stream({
-      ...options,
-      systemPrompt: enhancedSystemPrompt,
-      conversationMessages,
-    });
+    const streamResult = await provider.stream({
+      ...options,
+      systemPrompt: enhancedSystemPrompt,
+      conversationMessages,
+    });

This keeps the richer prompt where tools are truly usable, and avoids confusing models with nonfunctional tool instructions.

♻️ Duplicate comments (6)
src/lib/constants/enums.ts (1)

101-113: Claude 4.5 Haiku enum entry now correctly aligned with token maps

AnthropicModels.CLAUDE_4_5_HAIKU = "claude-haiku-4-5-20251001" matches the new token-limit keys in tokens.ts and the documented model ID, fixing the earlier enum/token mismatch and avoiding silent fallback to default token limits. Based on learnings, this centralization keeps model IDs consistent across enums and token constants.

src/lib/constants/tokens.ts (1)

76-140: Claude 4.5 Haiku token limits now consistent across providers

The new entries for "claude-haiku-4-5-20251001" (Anthropic/Vertex) and "anthropic.claude-haiku-4-5-20251001-v1:0" (Bedrock) align with the enum ID and Bedrock model id, so TokenUtils.getProviderTokenLimit() will now correctly return 8192 instead of the DEFAULT fallback for this model family. This closes the earlier enum/token mismatch for Claude 4.5 Haiku.

SDK_STREAM_BUG_FIX_SUMMARY.md (1)

4-4: Date has been corrected.

The document date now correctly shows "November 27, 2025" which aligns with the PR creation date.

HAYSTACK_MULTIMODAL_ANALYSIS.md (1)

55-63: Fix table structure mismatch.

The table header shows 3 columns (Feature, Component, Status), but the data rows have 4 values. Looking at the data:

  • Line 59: PDF to Image | PDFToImage | pdf2image | ✅ Full Support

It appears the table should have 4 columns: Feature, Component, Library, Status.

Apply this fix:

-| Feature           | Component         | Status    |
-| ----------------- | ----------------- | --------- |
+| Feature           | Component         | Library   | Status          |
+| ----------------- | ----------------- | --------- | --------------- |
 | PDF to Image      | `PDFToImage`      | pdf2image | ✅ Full Support |
src/lib/providers/litellm.ts (1)

290-320: Error chunks from fullStream are still ignored in the transformer.

The transformed stream handles textDelta chunks and logs tool-call-streaming-start, and falls back to raw string chunks, but it still doesn’t inspect chunk.type === "error" from result.fullStream. That means provider/library‑level stream errors can be silently swallowed by the generator.

You can reuse the earlier suggestion and add an error branch before the textDelta handling:

for await (const chunk of streamToUse) {
  if (chunk && typeof chunk === "object") {
    if (chunk.type === "error") {
      const errorChunk = chunk as { type: "error"; error: Record<string, unknown> };
      const errorMessage =
        (errorChunk.error && typeof errorChunk.error.message === "string"
          ? errorChunk.error.message
          : "LiteLLM streaming error");
      throw new Error(`LiteLLM streaming error: ${errorMessage}`);
    }

    if ("textDelta" in chunk) {
      const textDelta = (chunk as { textDelta: string }).textDelta;
      if (textDelta) {
        yield { content: textDelta };
      }
    } else if (chunk.type === "tool-call-streaming-start") {
      // existing logging…
    }
  } else if (typeof chunk === "string") {
    yield { content: chunk };
  }
}

This keeps the stream contract the same while surfacing errors instead of continuing silently.

src/lib/core/modules/TelemetryHandler.ts (1)

247-252: Missing error field in toolResults type assertion.

The type assertion is missing the error field, which exists in tool result types elsewhere. This was flagged in a previous review.

         toolResults as Array<{
           toolCallId?: string;
           toolName?: string;
           result?: unknown;
+          error?: string;
           [key: string]: unknown;
         }>,
🧹 Nitpick comments (18)
OLLAMA_TEST_VERIFICATION.md (1)

1-75: Clear regression scenarios; consider turning into executable tests

The four scenarios comprehensively document the options.messages/options.prompt precedence and parity between doGenerate/doStream. As a follow-up, consider adding automated tests that mirror these cases so future refactors can’t regress this behavior.

OLLAMA_FIX_SUMMARY.md (1)

1-71: Prefer repo-relative paths over local absolute paths

In “Files Modified”, the path currently includes a local absolute path (/Users/.../neurolink-fork/...). Consider switching this to a repo-relative path like src/lib/providers/ollama.ts so the doc stays accurate for all contributors.

src/lib/core/modelConfiguration.ts (1)

409-457: Double-check Ollama toolCapableModels matching strategy

The new toolCapableModels default uses bare family names (e.g. "llama3.1", "mistral", "qwen2.5") while MODEL_NAMES.OLLAMA uses full ids like "llama3.2:latest" / "llama3.1:8b". If the downstream tool-gating logic compares with strict string equality, these entries won’t match and tools may be incorrectly disabled; if it does prefix/substring matching, you’re fine.

Confirm how this list is consumed (e.g. equality vs includes/startsWith) and either:

  • align the defaults with the exact model ids you expect, or
  • make the consumer explicitly treat these as family prefixes.
docs/reference/provider-feature-compatibility.md (1)

454-456: Minor wording nit: avoid “CLI interface” tautology.

“CLI interface” is redundant (“I” already stands for interface). Consider shortening that bullet to “Custom tools via CLI” for cleaner wording.

MULTIMODAL_IMPLEMENTATION_GUIDE.md (1)

165-261: Clarify which refactor tasks are already implemented vs future work.

Sections “CRITICAL: Code Duplication Analysis”, “Solution 2: Modularize BaseProvider”, and the Phase‑1 checklist still read as if BaseProvider is a 2,351‑line monolith with duplicated executeStream multimodal logic, and that extracting buildMessagesForStream + moduleizing BaseProvider are future steps. In this PR those refactors are largely in place (MessageBuilder, StreamHandler, GenerationHandler, TelemetryHandler, ToolsManager, Utilities).

It would help to:

  • Explicitly mark these as “pre‑refactor findings” and
  • Add a short note or subsection calling out what this PR already implemented (with updated file/line references),

so this guide doesn’t look stale to someone reading it after the refactor.

PR_COMMENTS_IMPACT_ANALYSIS.md (1)

591-629: Keep impact report in sync with current code state (or pin to a baseline).

Several issues called out here as “Immediate (Blocks PR Merge)” / “DO NOT MERGE” (e.g., BaseProvider/streaming duplication, Claude 4.5 Haiku config, MultimodalInput.content, LiteLLM behavior) are at least partially touched by this PR’s refactors and model/typing updates. To avoid confusion for future readers:

  • Either update each issue to mark which ones are now resolved in this branch (with links/commits), or
  • Clearly state the codebase baseline (commit/branch) this analysis refers to, and that some items may already be fixed.

This keeps the report actionable without contradicting the current implementation.

MULTIMODALITY_GAP_ANALYSIS.md (1)

34-138: Consider flagging pre‑refactor analysis vs current implementation.

Sections “0. CRITICAL: CURRENT ARCHITECTURE ISSUES” and “0.3 Refactoring Required BEFORE Adding Features” accurately describe the pre‑refactor state (large BaseProvider, duplicated multimodal detection, missing modularization), but this PR now introduces the modules and helpers that those sections recommend.

To prevent confusion:

  • Add a short note near the top or in 0.3/15.x clarifying that this is a January 2025 gap analysis,
  • And briefly point to the follow‑up implementation docs / PR (e.g., MULTIMODAL_IMPLEMENTATION_GUIDE + current modularized BaseProvider) showing which items are now complete.

That keeps the document historically accurate without conflicting with the refactored architecture.

src/lib/providers/litellm.ts (1)

158-166: Update executeStream comment to match new tools behavior.

The docstring still says “Note: This is only used when tools are disabled”, but the implementation now conditionally enables tools (shouldUseTools and getAllTools()) for LiteLLM streams.

Consider updating the comment to something like “Provider‑specific streaming implementation (with optional tools)” so it doesn’t mislead future readers.

src/lib/core/modules/ToolsManager.ts (2)

169-249: Tone down logging of full tool inputs to avoid noisy/PII‑heavy logs.

processDirectTools wraps tools and logs input: params and later entire result (stringified) on debug, which may include large payloads or sensitive data (file contents, customer data, secrets), and can bloat logs.

Since you already have getKeysAsString/getKeyCount and truncate results elsewhere, consider:

  • Logging only structural info for params (type, key count, key names) rather than the full object, and
  • Keeping truncation for results (as you already do) or mirroring the same pattern for params.

For example:

logger.debug(`Direct tool:start event emitted for ${toolName}`, {
  toolName,
  inputKeys: params && typeof params === "object"
    ? Object.keys(params as Record<string, unknown>).slice(0, 10)
    : undefined,
  hasEmitter: !!emitter,
});

This keeps traces useful while reducing risk of leaking sensitive data and keeping logs manageable.


559-708: External MCP tool integration is robust; just the same logging caveat applies.

The external‑MCP path correctly:

  • Wraps JSON Schema via jsonSchema (with optional fixSchemaForOpenAIStrictMode),
  • Delegates execution through neurolink.executeExternalMCPTool, and
  • Emits tool:start / tool:end events (including error cases).

Same as for direct tools, you might want to avoid logging full params and full result bodies here (or truncate aggressively), especially since external MCP tools may operate on large or sensitive documents.

src/lib/types/generateTypes.ts (1)

13-13: Update import to use multimodal.js per deprecation guidance in content.ts.

The import from ./content.js is technically valid because content.ts re-exports Content from multimodal.ts for backward compatibility. However, content.ts is marked as deprecated with explicit guidance to import from ./multimodal.js in new code. Update the import to align with the preferred pattern:

import type { Content } from "./multimodal.js";
src/lib/providers/huggingFace.ts (1)

161-252: Enhanced system prompt for tools is computed but never applied to messages

prepareStreamOptions builds an enhancedSystemPrompt, but buildMessagesForStream(options) still uses the original options.systemPrompt. As a result, the extra tool‑calling guidance is not reflected in the actual messages.

You could apply the enhanced system prompt when building messages, e.g.:

   const streamOptions = this.prepareStreamOptions(options, analysisSchema);

-  // Build message array from options with multimodal support
-  // Using protected helper from BaseProvider to eliminate code duplication
-  const messages = await this.buildMessagesForStream(options);
+  // Build message array from options with multimodal support,
+  // ensuring we use the enhanced system prompt when tools are supported
+  const optionsWithEnhancedSystem: StreamOptions = {
+    ...options,
+    systemPrompt: streamOptions.system ?? options.systemPrompt,
+  };
+
+  const messages = await this.buildMessagesForStream(optionsWithEnhancedSystem);

This keeps the centralized message building while making the HuggingFace‑specific tool instructions effective.

test/run-all-providers-sequential.sh (1)

63-63: Unused variable PROVIDER_START.

PROVIDER_START is set but never used. Either remove it or use it to calculate per-provider duration (currently extracted from log file instead).

-  PROVIDER_START=$(date +%s)
+  # Per-provider duration is extracted from log output instead

Or use it for fallback duration calculation:

   PROVIDER_START=$(date +%s)
   
   # Run test and capture output
   if npx tsx test/continuous-test-suite.ts --provider "$provider" 2>&1 | tee "$LOG_FILE"; then
+    PROVIDER_END=$(date +%s)
+    MEASURED_DURATION=$((PROVIDER_END - PROVIDER_START))
     PASS_RATE=$(extract_pass_rate "$LOG_FILE")
-    DURATION=$(extract_duration "$LOG_FILE")
+    DURATION=$(extract_duration "$LOG_FILE")
+    DURATION=${DURATION:-$MEASURED_DURATION}  # Fallback if extraction fails
src/lib/adapters/providerImageAdapter.ts (1)

8-8: Confirm Content shape still matches convertToContent expectations (and consider centralizing model lists).

The switch to ../types/multimodal.js for Content plus the expanded vision model lists look fine, but convertToContent assumes Content supports { type: "text" | "image"; text?: string; data?: Buffer | string; mediaType?: string }. If the new multimodal types diverge (e.g., prefer image over data), this could silently mis-shape content for downstream providers.

Also, the expanded VISION_CAPABILITIES (mistral/bedrock/vertex) are now fairly large; if similar model sets are declared elsewhere (tokens/registry), consider centralizing them to avoid drift.

Also applies to: 130-148, 168-205

src/lib/utils/pdfProcessor.ts (1)

253-260: External CDN dependency introduces reliability and security concerns.

Loading fonts from cdn.jsdelivr.net at runtime creates an external dependency that could:

  1. Fail in air-gapped/offline environments
  2. Introduce latency
  3. Present a supply chain security risk

Consider bundling standard fonts locally or making the font URL configurable:

+    const standardFontDataUrl = options?.standardFontDataUrl || 
+      `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/standard_fonts/`;
+
     const loadingTask = pdfjs.getDocument({
       data: new Uint8Array(pdfBuffer),
       useSystemFonts: true,
-      standardFontDataUrl: `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/standard_fonts/`,
+      standardFontDataUrl,
     });
src/lib/core/baseProvider.ts (1)

256-268: Dead code: setTimeout always returns a truthy value.

The check if (!timeoutId) on line 262 will never be true since setTimeout always returns a positive integer (Node.js) or a Timeout object. This branch is unreachable.

-                    await new Promise((resolve, reject) => {
-                      const timeoutId = setTimeout(
-                        resolve,
-                        Math.random() * 9 + 1,
-                      );
-                      // Handle potential timeout issues
-                      if (!timeoutId) {
-                        reject(new Error("Failed to create timeout"));
-                      }
-                    }).catch((err) => {
-                      logger.error("Error in streaming delay:", err);
-                    });
+                    await new Promise((resolve) =>
+                      setTimeout(resolve, Math.random() * 9 + 1)
+                    );
src/lib/providers/ollama.ts (1)

1049-1057: Silently dropping image content in OpenAI-compatible mode may confuse users.

When multimodal messages contain images, they're converted to empty strings (line 1051) without warning. Users expecting vision support in OpenAI-compatible mode will get degraded results with no indication why.

Consider adding a warning log when images are present but will be ignored.

+        // Warn if images are being dropped in OpenAI-compatible mode
+        const hasImages = multimodalMessages.some((msg) =>
+          Array.isArray(msg.content) &&
+          msg.content.some((c) => (c as { type?: string }).type === "image")
+        );
+        if (hasImages) {
+          logger.warn(
+            "Ollama OpenAI-compatible mode does not support images. Image content will be ignored.",
+          );
+        }
+
         // Convert multimodal messages to text (OpenAI-compatible mode doesn't support images in /v1/chat/completions for Ollama)
         const content = multimodalMessages
           .map((msg) => (typeof msg.content === "string" ? msg.content : ""))
           .join("\n");
src/lib/core/modules/Utilities.ts (1)

238-239: Specify radix for parseInt to avoid potential parsing issues.

While this works correctly for the expected input, explicitly specifying base 10 is a best practice and prevents issues with leading zeros.

-    const value = parseInt(timeoutStr);
+    const value = parseInt(timeoutStr, 10);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63b3e43 and 07e1b37.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (61)
  • CLAUDE.md (1 hunks)
  • CODE_QUALITY_FIXES.md (1 hunks)
  • COMMIT_ANALYSIS_REPORT.md (1 hunks)
  • HAYSTACK_MULTIMODAL_ANALYSIS.md (1 hunks)
  • MULTIMODALITY_GAP_ANALYSIS.md (1 hunks)
  • MULTIMODAL_IMPLEMENTATION_GUIDE.md (1 hunks)
  • OLLAMA_FIX_SUMMARY.md (1 hunks)
  • OLLAMA_TEST_VERIFICATION.md (1 hunks)
  • PR_COMMENTS_IMPACT_ANALYSIS.md (1 hunks)
  • PR_COMMENTS_SOLUTION_PLAN.md (1 hunks)
  • PR_REVIEW_FIXES_SUMMARY.md (1 hunks)
  • README.md (1 hunks)
  • SDK_STREAM_BUG_FIX_SUMMARY.md (1 hunks)
  • docs/getting-started/API-REFERENCE.md (0 hunks)
  • docs/getting-started/provider-setup.md (0 hunks)
  • docs/reference/provider-feature-compatibility.md (1 hunks)
  • docs/sdk/api-reference.md (0 hunks)
  • package.json (3 hunks)
  • scripts/env-validation.cjs (21 hunks)
  • src/cli/factories/commandFactory.ts (1 hunks)
  • src/lib/adapters/providerImageAdapter.ts (6 hunks)
  • src/lib/agent/directTools.ts (1 hunks)
  • src/lib/constants/enums.ts (1 hunks)
  • src/lib/constants/tokens.ts (3 hunks)
  • src/lib/core/baseProvider.ts (11 hunks)
  • src/lib/core/constants.ts (2 hunks)
  • src/lib/core/modelConfiguration.ts (1 hunks)
  • src/lib/core/modules/GenerationHandler.ts (1 hunks)
  • src/lib/core/modules/MessageBuilder.ts (1 hunks)
  • src/lib/core/modules/StreamHandler.ts (1 hunks)
  • src/lib/core/modules/TelemetryHandler.ts (1 hunks)
  • src/lib/core/modules/ToolsManager.ts (1 hunks)
  • src/lib/core/modules/Utilities.ts (1 hunks)
  • src/lib/factories/providerRegistry.ts (1 hunks)
  • src/lib/mcp/servers/agent/directToolsServer.ts (0 hunks)
  • src/lib/models/modelRegistry.ts (1 hunks)
  • src/lib/neurolink.ts (4 hunks)
  • src/lib/providers/amazonBedrock.ts (3 hunks)
  • src/lib/providers/anthropic.ts (1 hunks)
  • src/lib/providers/azureOpenai.ts (1 hunks)
  • src/lib/providers/googleAiStudio.ts (1 hunks)
  • src/lib/providers/googleVertex.ts (1 hunks)
  • src/lib/providers/huggingFace.ts (1 hunks)
  • src/lib/providers/litellm.ts (5 hunks)
  • src/lib/providers/mistral.ts (2 hunks)
  • src/lib/providers/ollama.ts (8 hunks)
  • src/lib/providers/openAI.ts (1 hunks)
  • src/lib/providers/openaiCompatible.ts (1 hunks)
  • src/lib/types/content.ts (1 hunks)
  • src/lib/types/conversation.ts (1 hunks)
  • src/lib/types/generateTypes.ts (2 hunks)
  • src/lib/types/index.ts (1 hunks)
  • src/lib/types/multimodal.ts (1 hunks)
  • src/lib/types/streamTypes.ts (3 hunks)
  • src/lib/utils/imageProcessor.ts (1 hunks)
  • src/lib/utils/messageBuilder.ts (4 hunks)
  • src/lib/utils/pdfProcessor.ts (4 hunks)
  • test/TESTING_SCRIPTS.md (1 hunks)
  • test/continuous-test-suite.ts (10 hunks)
  • test/run-all-providers-sequential.sh (1 hunks)
  • test/test-all-providers.sh (1 hunks)
💤 Files with no reviewable changes (4)
  • docs/getting-started/provider-setup.md
  • src/lib/mcp/servers/agent/directToolsServer.ts
  • docs/getting-started/API-REFERENCE.md
  • docs/sdk/api-reference.md
🧰 Additional context used
🧠 Learnings (17)
📚 Learning: 2025-09-17T17:55:15.261Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 173
File: src/lib/index.ts:16-16
Timestamp: 2025-09-17T17:55:15.261Z
Learning: In src/lib/types/providers.ts, ProviderConfig was renamed to AIModelProviderConfig to deduplicate type names, as there was an existing ProviderConfig type that better suited the "ProviderConfig" name. This was an intentional breaking change for better type organization.

Applied to files:

  • src/lib/providers/googleAiStudio.ts
  • src/lib/providers/mistral.ts
  • src/cli/factories/commandFactory.ts
  • src/lib/providers/openaiCompatible.ts
  • src/lib/core/modules/MessageBuilder.ts
  • src/lib/core/modelConfiguration.ts
  • src/lib/providers/huggingFace.ts
  • src/lib/utils/imageProcessor.ts
  • src/lib/types/generateTypes.ts
  • src/lib/providers/googleVertex.ts
  • src/lib/providers/anthropic.ts
  • src/lib/core/modules/TelemetryHandler.ts
  • README.md
  • src/lib/providers/azureOpenai.ts
  • OLLAMA_FIX_SUMMARY.md
  • src/lib/factories/providerRegistry.ts
  • src/lib/core/baseProvider.ts
  • src/lib/core/constants.ts
  • src/lib/providers/litellm.ts
  • docs/reference/provider-feature-compatibility.md
  • src/lib/types/conversation.ts
  • src/lib/adapters/providerImageAdapter.ts
  • src/lib/types/streamTypes.ts
  • src/lib/providers/openAI.ts
  • src/lib/models/modelRegistry.ts
  • src/lib/types/multimodal.ts
  • src/lib/types/index.ts
  • src/lib/core/modules/GenerationHandler.ts
  • src/lib/core/modules/ToolsManager.ts
  • src/lib/providers/ollama.ts
  • src/lib/types/content.ts
📚 Learning: 2025-09-01T22:58:39.149Z
Learnt from: sudharsan-juspay
Repo: juspay/neurolink PR: 140
File: src/lib/core/types.ts:198-203
Timestamp: 2025-09-01T22:58:39.149Z
Learning: In src/lib/core/types.ts, StreamOptions (imported from streamTypes.js) and StreamingOptions are intentionally different types with different use cases. StreamingOptions is for unified AI requests with multiple provider configurations, while StreamOptions is for individual streaming operations.

Applied to files:

  • src/lib/providers/googleAiStudio.ts
  • src/lib/providers/openaiCompatible.ts
  • src/lib/providers/huggingFace.ts
  • src/lib/types/generateTypes.ts
  • src/lib/providers/googleVertex.ts
  • src/lib/providers/anthropic.ts
  • src/lib/utils/messageBuilder.ts
  • src/lib/providers/litellm.ts
  • src/lib/core/modules/StreamHandler.ts
  • src/lib/core/modules/Utilities.ts
  • src/lib/types/streamTypes.ts
  • src/lib/neurolink.ts
📚 Learning: 2025-09-02T13:50:42.770Z
Learnt from: YasmeenOgo
Repo: juspay/neurolink PR: 145
File: src/lib/core/types.ts:0-0
Timestamp: 2025-09-02T13:50:42.770Z
Learning: The APIVersions enum in src/lib/core/types.ts now contains comprehensive API version constants for all major AI providers: Azure OpenAI (latest, stable, legacy), OpenAI (current, beta), Google AI (current, beta), and Anthropic (current). This centralization helps avoid API version drift across the codebase.

Applied to files:

  • src/lib/providers/googleAiStudio.ts
  • src/lib/providers/openaiCompatible.ts
  • src/lib/constants/enums.ts
  • src/lib/providers/anthropic.ts
  • README.md
  • src/lib/providers/azureOpenai.ts
  • src/lib/factories/providerRegistry.ts
  • src/lib/core/constants.ts
  • src/lib/providers/litellm.ts
  • docs/reference/provider-feature-compatibility.md
  • src/lib/models/modelRegistry.ts
  • src/lib/types/index.ts
  • src/lib/providers/ollama.ts
📚 Learning: 2025-09-17T18:14:34.960Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 173
File: src/lib/types/index.ts:58-62
Timestamp: 2025-09-17T18:14:34.960Z
Learning: RajuSudhar explained that in the Neurolink codebase, there are multiple ProviderConfig types causing inconsistency. One existing ProviderConfig type better suited the "ProviderConfig" name, so they renamed the less-suitable one to AIModelProviderConfig to free up the name. Adding backward compatibility aliases would worsen naming inconsistency rather than help. The remaining duplicates will be systematically deduplicated in the 07-Types-Module.md TODO as part of their phased refactor approach.

Applied to files:

  • src/lib/providers/openaiCompatible.ts
  • src/lib/providers/anthropic.ts
  • README.md
  • src/lib/providers/azureOpenai.ts
  • src/lib/factories/providerRegistry.ts
  • docs/reference/provider-feature-compatibility.md
  • src/lib/adapters/providerImageAdapter.ts
  • CLAUDE.md
  • src/lib/providers/openAI.ts
  • MULTIMODAL_IMPLEMENTATION_GUIDE.md
  • MULTIMODALITY_GAP_ANALYSIS.md
📚 Learning: 2025-09-24T06:42:06.088Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 185
File: src/lib/evaluation/contextBuilder.ts:79-85
Timestamp: 2025-09-24T06:42:06.088Z
Learning: In the NeuroLink codebase, using `(options.prompt || [])` pattern for handling potentially undefined prompt arrays is the preferred approach over extracting to a normalized variable when building conversation history in the ContextBuilder class.

Applied to files:

  • src/lib/core/modules/MessageBuilder.ts
  • src/lib/providers/amazonBedrock.ts
  • src/lib/utils/messageBuilder.ts
  • src/lib/neurolink.ts
  • src/lib/providers/ollama.ts
📚 Learning: 2025-09-24T07:26:41.988Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 185
File: src/lib/evaluation/prompts.ts:86-101
Timestamp: 2025-09-24T07:26:41.988Z
Learning: In the neurolink codebase, maintainer amreetkhuntia consistently prefers to keep template literal indentation in LLM prompts (including evaluation prompts in src/lib/evaluation/prompts.ts) for readability, even when it results in extra whitespace in the output, as LLMs can parse and understand the content correctly.

Applied to files:

  • src/lib/core/modules/MessageBuilder.ts
📚 Learning: 2025-09-24T06:41:27.575Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 185
File: src/lib/evaluation/contextBuilder.ts:53-63
Timestamp: 2025-09-24T06:41:27.575Z
Learning: In the NeuroLink codebase, `LanguageModelV1CallOptions.prompt` is always present and never undefined, so defensive checks are not needed when accessing this property.

Applied to files:

  • src/lib/core/modules/MessageBuilder.ts
  • src/lib/providers/ollama.ts
📚 Learning: 2025-09-01T06:15:59.759Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 133
File: src/lib/core/types.ts:208-210
Timestamp: 2025-09-01T06:15:59.759Z
Learning: The middleware?: MiddlewareFactoryOptions field is already present in both TextGenerationOptions and StreamOptions interfaces in the neurolink codebase.

Applied to files:

  • src/lib/types/generateTypes.ts
  • src/lib/utils/messageBuilder.ts
📚 Learning: 2025-09-10T08:22:11.910Z
Learnt from: sudharsan-juspay
Repo: juspay/neurolink PR: 160
File: src/lib/providers/index.ts:43-44
Timestamp: 2025-09-10T08:22:11.910Z
Learning: In the Neurolink project, type deduplication across modules (like ProviderName definitions) should be handled as separate tasks rather than mixed with other refactoring efforts, as there are multiple such occurrences throughout the codebase that need systematic cleanup.

Applied to files:

  • src/lib/core/modules/TelemetryHandler.ts
  • MULTIMODALITY_GAP_ANALYSIS.md
📚 Learning: 2025-09-28T21:00:08.243Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 174
File: src/lib/mcp/contracts/mcpContract.ts:0-0
Timestamp: 2025-09-28T21:00:08.243Z
Learning: The src/lib/mcp/contracts/mcpContract.ts file was completely removed during the MCP types refactor in PR #174, with its types moved to centralized modules like src/lib/types/mcpTypes.ts and src/lib/types/index.ts.

Applied to files:

  • src/lib/types/conversation.ts
  • src/lib/types/content.ts
📚 Learning: 2025-11-04T22:14:18.719Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-11-04T22:14:18.719Z
Learning: In the juspay/neurolink repository, all new type definitions must be placed in src/lib/types/. New type definitions outside this directory should be flagged and blocked in code reviews.

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-09-07T09:14:50.565Z
Learnt from: Yaswanth-2874
Repo: juspay/neurolink PR: 149
File: test/conversation-memory-test.js:66-69
Timestamp: 2025-09-07T09:14:50.565Z
Learning: In the juspay/neurolink repository, test files don't need defensive type guards for known API contracts. The user prefers to keep test code simpler without additional safety checks when the data structure is guaranteed.

Applied to files:

  • test/continuous-test-suite.ts
📚 Learning: 2025-11-05T20:31:04.103Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 227
File: src/lib/utils/redis.ts:15-15
Timestamp: 2025-11-05T20:31:04.103Z
Learning: In the juspay/neurolink repository, type centralization rules (requiring types in src/lib/types/) do not apply to private, non-exported utility types used within a single file. Simple readability helpers like `type RedisClient = ReturnType<typeof createClient>` should remain in their implementation file when they are not exported and only used locally. Only exported types shared across modules, business/domain types, and public API types require centralization.

Applied to files:

  • src/lib/types/index.ts
📚 Learning: 2025-09-01T14:12:14.227Z
Learnt from: swaroopvarma1
Repo: juspay/neurolink PR: 141
File: docs/REAL-TIME-SPEECH-AGENTS.md:124-149
Timestamp: 2025-09-01T14:12:14.227Z
Learning: In the NeuroLink Speech-to-Speech agent system, the team prefers simple void-returning APIs (sendAudioFrame, sendText, flush) over Promise-based backpressure mechanisms, prioritizing ease of use and implementation simplicity for real-time speech processing.

Applied to files:

  • MULTIMODAL_IMPLEMENTATION_GUIDE.md
📚 Learning: 2025-11-17T13:53:20.209Z
Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 237
File: memory-bank/tts-provider-implementation-plan.md:92-106
Timestamp: 2025-11-17T13:53:20.209Z
Learning: In PR 237's TTS modality implementation approach, TTS functionality uses GOOGLE_AI_API_KEY (not GOOGLE_TTS_API_KEY) when using the google-ai provider. TTS is implemented as an output modality that leverages the existing google-ai provider authentication.

Applied to files:

  • MULTIMODAL_IMPLEMENTATION_GUIDE.md
📚 Learning: 2025-10-01T07:58:00.270Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 197
File: neurolink-demo/middleware/guardrails-precall-demo.ts:123-145
Timestamp: 2025-10-01T07:58:00.270Z
Learning: Demo files in the neurolink-demo/ directory can be ignored and should not be subject to detailed code review scrutiny.

Applied to files:

  • MULTIMODALITY_GAP_ANALYSIS.md
📚 Learning: 2025-10-01T07:57:56.458Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 197
File: neurolink-demo/middleware/guardrails-precall-demo.ts:112-118
Timestamp: 2025-10-01T07:57:56.458Z
Learning: Demo files in the neurolink-demo directory should be ignored during code reviews, as they are for demonstration purposes only.

Applied to files:

  • MULTIMODALITY_GAP_ANALYSIS.md
🧬 Code graph analysis (11)
src/lib/providers/mistral.ts (1)
src/lib/utils/providerConfig.ts (1)
  • getProviderModel (178-180)
src/lib/providers/amazonBedrock.ts (4)
src/lib/types/streamTypes.ts (1)
  • StreamOptions (156-233)
src/lib/utils/multimodalOptionsBuilder.ts (1)
  • buildMultimodalOptions (45-70)
src/lib/utils/messageBuilder.ts (1)
  • buildMultimodalMessagesArray (436-728)
src/lib/types/providers.ts (1)
  • BedrockMessage (482-485)
test/test-all-providers.sh (3)
src/lib/core/baseProvider.ts (1)
  • generate (465-506)
src/lib/neurolink.ts (1)
  • generate (1649-1901)
src/lib/providers/amazonBedrock.ts (1)
  • generate (164-250)
src/lib/types/generateTypes.ts (1)
src/lib/types/multimodal.ts (1)
  • Content (193-199)
src/lib/providers/litellm.ts (4)
src/lib/types/index.ts (1)
  • StreamResult (183-183)
src/lib/types/streamTypes.ts (1)
  • StreamResult (239-280)
src/lib/utils/logger.ts (2)
  • logger (358-401)
  • error (239-241)
src/lib/core/constants.ts (1)
  • DEFAULT_MAX_STEPS (10-10)
src/lib/core/modules/Utilities.ts (3)
src/lib/utils/parameterValidation.ts (2)
  • createValidationSummary (716-734)
  • ValidationError (29-46)
src/lib/core/constants.ts (1)
  • STEP_LIMITS (13-17)
src/lib/utils/tokenLimits.ts (1)
  • getSafeMaxTokens (12-60)
src/lib/types/streamTypes.ts (1)
src/lib/types/multimodal.ts (1)
  • Content (193-199)
src/lib/models/modelRegistry.ts (2)
src/lib/types/index.ts (1)
  • AIProviderName (9-9)
src/lib/index.ts (1)
  • AIProviderName (38-38)
src/lib/types/multimodal.ts (1)
src/lib/types/content.ts (20)
  • TextContent (20-20)
  • ImageContent (21-21)
  • CSVContent (22-22)
  • PDFContent (23-23)
  • AudioContent (24-24)
  • VideoContent (25-25)
  • Content (26-26)
  • MultimodalInput (27-27)
  • MultimodalMessage (28-28)
  • VisionCapability (29-29)
  • ProviderImageFormat (30-30)
  • ProcessedImage (31-31)
  • ProviderMultimodalPayload (32-32)
  • isTextContent (34-34)
  • isImageContent (35-35)
  • isCSVContent (36-36)
  • isPDFContent (37-37)
  • isAudioContent (38-38)
  • isVideoContent (39-39)
  • isMultimodalInput (40-40)
src/lib/core/modules/GenerationHandler.ts (5)
src/lib/types/index.ts (5)
  • AIProviderName (9-9)
  • StandardRecord (16-16)
  • UnknownRecord (50-50)
  • ToolResult (63-63)
  • ToolResult (178-178)
src/lib/types/generateTypes.ts (2)
  • TextGenerationOptions (183-228)
  • EnhancedGenerateResult (261-264)
src/lib/types/tools.ts (1)
  • ToolCallObject (221-228)
src/lib/types/providers.ts (2)
  • AISDKGenerateResult (410-420)
  • ExtendedTool (405-405)
src/lib/types/streamTypes.ts (1)
  • ToolResult (77-91)
src/lib/core/modules/ToolsManager.ts (3)
src/lib/types/index.ts (4)
  • AIProviderName (9-9)
  • ToolArgs (61-61)
  • StandardRecord (16-16)
  • JsonObject (53-53)
src/lib/utils/transformationUtils.ts (2)
  • getKeyCount (516-518)
  • getKeysAsString (504-510)
src/lib/utils/schemaConversion.ts (1)
  • convertJsonSchemaToZod (74-174)
🪛 LanguageTool
PR_COMMENTS_SOLUTION_PLAN.md

[uncategorized] ~311-~311: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...ent - Risk: Low - Widening type is backward compatible - Impact: Medium - Enables proper m...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[uncategorized] ~698-~698: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...ocumentation (Low Priority) 📚 11. Fix markdown tables - 1 min 12. Remove local pat...

(MARKDOWN_NNP)

PR_COMMENTS_IMPACT_ANALYSIS.md

[uncategorized] ~613-~613: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...(Documentation/non-functional) 10. Fix markdown table (Issue #3) 11. Remove local path ...

(MARKDOWN_NNP)


[style] ~624-~624: Consider using a different verb for a more formal wording.
Context: ...ssues:** 4 critical issues that must be fixed before merge Data Integrity Issues:...

(FIX_RESOLVE)

CODE_QUALITY_FIXES.md

[grammar] ~50-~50: Use a hyphen to join words.
Context: ...(line 154) ### Problem The two message building methods had inconsistent fallba...

(QB_NEW_EN_HYPHEN)


[grammar] ~77-~77: Use a hyphen to join words.
Context: ...tilized as a fallback across all message building operations - **Backward Compati...

(QB_NEW_EN_HYPHEN)

HAYSTACK_MULTIMODAL_ANALYSIS.md

[grammar] ~687-~687: Ensure spelling is correct
Context: ...** (cost/privacy flexibility) ### What NeuroLink Does Better 1. **Vision model integrat...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

docs/reference/provider-feature-compatibility.md

[style] ~455-~455: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: .... CLI Business Tools - Custom tools via CLI interface #### Enterprise Features Tests (1 test...

(ACRONYM_TAUTOLOGY)

PR_REVIEW_FIXES_SUMMARY.md

[grammar] ~70-~70: Use a hyphen to join words.
Context: ...ct:** Consistent behavior across message building methods --- ### 🟡 Minor Issu...

(QB_NEW_EN_HYPHEN)

MULTIMODAL_IMPLEMENTATION_GUIDE.md

[style] ~117-~117: Consider a different adjective to strengthen your wording.
Context: ...## Current Architecture Problems After deep analysis of the actual codebase impleme...

(DEEP_PROFOUND)


[style] ~172-~172: To elevate your writing, try using a synonym here.
Context: ...enance burden, difficult to understand, hard to extend ### Solution Architecture #...

(HARD_TO)


[uncategorized] ~1076-~1076: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...Pattern: Upload → Transcribe → Store as markdown with header Dependencies to Add: ...

(MARKDOWN_NNP)


[style] ~2034-~2034: Consider using a different verb for a more formal wording.
Context: ...lease Preparation - [ ] Run linter and fix issues: npm run lint - [ ] Run type c...

(FIX_RESOLVE)

MULTIMODALITY_GAP_ANALYSIS.md

[style] ~40-~40: Consider a different adjective to strengthen your wording.
Context: ...aintainability and extensibility After deep analysis of the actual codebase, **crit...

(DEEP_PROFOUND)


[style] ~719-~719: This adverb was used twice in the sentence. Consider removing one of them or replacing them with a synonym.
Context: ... - ❌ Only PCM streaming - ❌ Gemini Live only (no other providers) - ❌ No audio file ...

(ADVERB_REPETITION_PREMIUM)


[uncategorized] ~770-~770: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...xing After transcription: 1. Store as markdown document 2. Summarize by LLM 3. Chunk f...

(MARKDOWN_NNP)

🪛 Shellcheck (0.11.0)
test/run-all-providers-sequential.sh

[warning] 63-63: PROVIDER_START appears unused. Verify use (or export if used externally).

(SC2034)

Comment thread src/lib/core/modules/MessageBuilder.ts
Comment thread src/lib/neurolink.ts
Comment thread src/lib/providers/amazonBedrock.ts
Comment thread src/lib/providers/ollama.ts Outdated
Comment thread src/lib/types/content.ts Outdated
Comment thread src/lib/utils/pdfProcessor.ts Outdated
Comment thread test/test-all-providers.sh
@murdore
murdore force-pushed the feat/all-multi-modality branch from 07e1b37 to dbf7518 Compare November 28, 2025 01:17
@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

Copilot AI review requested due to automatic review settings November 28, 2025 03:02
@murdore
murdore force-pushed the feat/all-multi-modality branch from dbf7518 to 81a5e44 Compare November 28, 2025 03:02
@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 61 out of 62 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

@murdore
murdore force-pushed the feat/all-multi-modality branch from 81a5e44 to feb411f Compare November 28, 2025 03:34
@murdore

murdore commented Nov 28, 2025

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/lib/providers/huggingFace.ts (1)

161-253: Enhanced tool system prompt is computed but never used in message building

prepareStreamOptions() builds an enhancedSystemPrompt and returns it as system, but executeStream() only uses streamOptions.tools/toolChoice and still calls buildMessagesForStream(options) with the original options.systemPrompt. This makes the HuggingFace‑specific tool instructions effectively dead and likely weaker for tool‑capable models.

Consider wiring the enhanced system prompt into the shared message builder, e.g.:

-    const streamOptions = this.prepareStreamOptions(options, analysisSchema);
-
-    // Build message array from options with multimodal support
-    // Using protected helper from BaseProvider to eliminate code duplication
-    const messages = await this.buildMessagesForStream(options);
+    const streamOptions = this.prepareStreamOptions(options, analysisSchema);
+
+    // Build message array from options with multimodal support
+    // Use enhanced system prompt when available to guide tool usage
+    const messages = await this.buildMessagesForStream({
+      ...options,
+      systemPrompt: streamOptions.system ?? options.systemPrompt,
+    });

This keeps tools wiring via streamOptions.tools while ensuring HuggingFace‑specific tool instructions actually reach the model.

src/lib/providers/amazonBedrock.ts (1)

171-239: Text-only generate() path ignores input.text when prompt is unset

In the non‑multimodal branch of generate(), the user message is built with content: [{ text: options.prompt }]. If callers use the input.text field without setting prompt (which is valid per TextGenerationOptions), Bedrock receives undefined as the user text, while the real input lives in input.text.

This is inconsistent with:

  • the multimodal builder, which uses options.prompt || options.input?.text || "", and
  • the streaming path, which uses options.input.text for text‑only input.

To align behaviors and avoid silent message loss, reuse the already‑computed input fallback here:

-      // Add user message to conversation - simple text-only case
-      const userMessage: BedrockMessage = {
-        role: "user",
-        content: [{ text: options.prompt }],
-      };
+      // Add user message to conversation - simple text-only case
+      const text = options.prompt || input?.text || "";
+      const userMessage: BedrockMessage = {
+        role: "user",
+        content: [{ text }],
+      };
       this.conversationHistory.push(userMessage);

This preserves prompt-first semantics while correctly falling back to input.text when no prompt is provided.

♻️ Duplicate comments (7)
HAYSTACK_MULTIMODAL_ANALYSIS.md (1)

39-63: Markdown tables render correctly after separator fix

The multimodal support tables (e.g., image processing at Line 55–Line 63) now have consistent header/separator/row column counts, so they should render cleanly in GitHub and docs tooling. No further changes needed here.

src/lib/providers/ollama.ts (1)

505-510: Past review issue resolved: totalPromptTokens is now properly computed.

Unlike the previous implementation where totalPromptTokens was declared as const and never updated, this version correctly estimates prompt tokens from the messages parameter and uses it appropriately in the finish event. The implementation now matches the non-streaming behavior.

src/lib/providers/litellm.ts (1)

296-313: Past review issue addressed: Error chunk handling is now implemented.

The code now checks for error chunks before processing text deltas and throws a descriptive error, resolving the previous concern about silent failures.

src/lib/core/modules/TelemetryHandler.ts (1)

247-252: Past review issue: Missing error field in toolResults type assertion.

The type assertion for toolResults is missing the error field that may be present on failed tool executions. This could cause type mismatches when storing failed tool results.

         toolResults as Array<{
           toolCallId?: string;
           toolName?: string;
           result?: unknown;
+          error?: string;
           [key: string]: unknown;
         }>,
src/lib/core/modules/Utilities.ts (1)

366-410: LGTM - Middleware extraction with proper type guards.

The method correctly handles the precedence of per-request over global middleware options, includes appropriate type guards for Date/RegExp edge cases, and ensures configuration is present before returning. The default global settings (collectStats, continueOnError) are sensible.

src/lib/types/content.ts (1)

1-45: LGTM - Proper separation of type and value exports.

The file correctly addresses the previous concern by using export type { ... } for pure type exports and regular export { ... } for runtime type guard functions. The deprecation notice with migration guidance is helpful for gradual migration.

src/lib/core/modules/GenerationHandler.ts (1)

125-221: LGTM - Robust tool information extraction with proper null handling.

The method handles various tool call/result shapes from different SDK versions, building a map of tool call arguments for matching with results. The use of ?? at line 213 correctly preserves falsy values like 0 or false while only defaulting null/undefined.

🧹 Nitpick comments (34)
src/lib/core/constants.ts (1)

41-71: Validate updated provider maxTokens defaults and new mistral entry

The new per‑provider caps (Line 47, Line 59, Line 62, Line 68) look directionally sane and less extreme than the previous 500k defaults, but they now drive behavior in multiple places (e.g., guardrails in BaseProvider and any validation using PROVIDER_MAX_TOKENS). Two things to double‑check:

  • Ensure 128000 aligns with the actual max context for the default models you resolve for OpenAI/Azure/LiteLLM/Mistral so we don’t silently ask for more than the model supports.
  • Confirm any CLI or config‑level limits that still cap at 64000 are intentional (i.e., they’re a UX constraint, not an oversight), since they’re now lower than some provider defaults.

If these are meant as soft ceilings rather than hard model limits, a brief comment in this file would help future maintainers avoid assuming they are authoritative.

COMMIT_ANALYSIS_REPORT.md (1)

11-171: Keep “DO NOT MERGE” status and issue list in sync with actual code state

This report is useful, but once the listed critical issues are fixed in this PR (Ollama regression, Claude 4.5 Haiku config, MultimodalInput type, etc.), the persistent “🔴 DO NOT MERGE” status and counts will become stale. Consider either:

  • Updating this document as fixes land, or
  • Marking it clearly as a historical snapshot tied to a specific commit/phase.

That will avoid confusion for future reviewers who might assume the blockers still apply to release.

PR_COMMENTS_SOLUTION_PLAN.md (1)

22-373: Good, actionable mapping from review comments to concrete edits

This plan does a solid job of turning prior review comments into specific file/line‑level fixes, with clear testing notes and rough effort estimates. Once the fixes are implemented, you may want to:

  • Add a very short “status” section (e.g., completed / in‑progress per issue), or
  • Link from the PR description to this file so reviewers don’t miss it.

No code changes required; this is just a discoverability suggestion.

scripts/env-validation.cjs (2)

60-118: Leverage section/line info in diagnostics for .env.example parsing

parseEnvExample() correctly tracks currentSection and lineNumber (Line 75–Line 77) and passes both into validateEnvVariable (Line 113), but they’re currently unused in validation and issue messages. Using them in addIssue calls (e.g., including section + line in the message or as extra fields) would make it much easier to locate problematic entries in larger .env.example files, with no behavior change to the checker itself.


293-377: Provider config validation is helpful; treat ‘info’ severities as non-blocking by design

The split between:

  • info for missing optional vars and missing required vars on unconfigured providers (Line 358–Line 367), and
  • warning / error elsewhere

matches the “advisory, not hard‑fail” intent of this script. Just ensure downstream tooling (e.g., CI step that runs this) treats info issues as non‑fatal; otherwise, consider bumping missing required provider vars to warning only when that provider is selected as the default.

MULTIMODAL_IMPLEMENTATION_GUIDE.md (1)

312-445: Watch for drift between guide code snippets and actual type definitions

This guide captures a lot of concrete TypeScript fragments (e.g., MultimodalInput, Content, FileProcessingResult) with specific file/line references. After the BaseProvider/type refactors in this PR, these examples are accurate now, but they’re tightly coupled to implementation details and line numbers.

To keep this maintainable, consider:

  • Prefacing code blocks as “illustrative” rather than “source‑of‑truth”, and/or
  • Linking to the actual files instead of embedding line numbers in prose.

That way the guide stays useful even as internals evolve in future multimodal work.

src/cli/factories/commandFactory.ts (1)

44-67: Ensure new google-ai-studio provider alias is supported consistently across CLI UX

Adding "google-ai-studio" to commonOptions.provider.choices (Line 47–Line 63) exposes the new alias nicely for generate/stream/batch, but a couple of follow‑ups would keep things coherent:

  • The setup command’s provider positional (Line 907–Line 918) only lists "google-ai", not "google-ai-studio". If users are expected to run neurolink setup google-ai-studio, consider adding the alias there or documenting that setup still uses the canonical "google-ai" name.
  • The bash completion script generated in executeCompletion() still offers an older provider list (auto openai bedrock vertex googleVertex anthropic azure google-ai huggingface ollama mistral litellm) and omits both "google-ai-studio" and "openai-compatible"/"sagemaker". Keeping that list in sync with commonOptions.provider.choices would avoid confusing tab‑completion behavior.

Functionally the new choice is fine; this is about aligning all entry points around the same provider naming surface.

src/lib/types/index.ts (1)

157-185: Minor: streamTypes comment no longer matches selective exports

The comment says stream/tool domain types are exported via wildcard from ./streamTypes.js, but you now export a curated set of types below. Consider updating the comment to reflect the selective export to avoid confusion for future readers.

OLLAMA_FIX_SUMMARY.md (1)

1-70: Ollama fix summary is clear; consider avoiding brittle line/path references

The before/after snippets and explanation of options.messages vs options.prompt make the bug and fix very understandable. To keep this doc from going stale as the code moves, you might drop the hard‑coded line numbers and local absolute file path at the bottom or replace them with a relative path only.

CODE_QUALITY_FIXES.md (1)

7-124: Utilities/MessageBuilder fix summary is precise and useful

The before/after snippets for extractMiddlewareOptions and buildMessagesForStream clearly capture the behavioral changes (extra Date/RegExp guards and prompt fallback), which will help future debugging and audits. If you care about strict docs linting, you could optionally hyphenate phrases like “message-building methods” to satisfy tools like LanguageTool, but that’s purely cosmetic.

src/lib/types/streamTypes.ts (1)

4-5: Multimodal Content[] and streaming‑audio types are well integrated

Importing Content for input.content?: Content[] plus the new AudioInputSpec/AudioChunk streaming types cleanly extend StreamOptions/StreamResult for advanced multimodal and live‑audio use, and the comments clearly distinguish streaming audio from file‑based AudioContent. No issues from a typing or API‑shape perspective.

Also applies to: 128-155, 156-165

src/lib/core/modelConfiguration.ts (1)

433-449: Config‑driven toolCapableModels for Ollama is a good extension

Adding modelBehavior.toolCapableModels with env‑overridable defaults cleanly moves Ollama tool‑capability knowledge into configuration without affecting existing validation logic. This should make future tuning of tool‑capable models much easier.

src/lib/models/modelRegistry.ts (1)

205-248: Claude 4.5 Haiku registry entry looks good; consider wiring it into recommendations

The CLAUDE_4_5_HAIKU entry (capabilities, pricing, limits, aliases, metadata) is consistent with the other Anthropic models and fits the “fast general model with vision” role.

Right now, USE_CASE_RECOMMENDATIONS only reference 3.5 Sonnet/Haiku. You may want to include AnthropicModels.CLAUDE_4_5_HAIKU in relevant buckets (e.g., conversation, fast, possibly cost-effective) so the CLI surfaces it in recommendations, for example:

   conversation: [
     OpenAIModels.GPT_4O,
-    AnthropicModels.CLAUDE_3_5_SONNET,
-    AnthropicModels.CLAUDE_3_5_HAIKU,
+    AnthropicModels.CLAUDE_3_5_SONNET,
+    AnthropicModels.CLAUDE_4_5_HAIKU,
   ],
@@
   fast: [
     OpenAIModels.GPT_4O_MINI,
     GoogleAIModels.GEMINI_2_5_FLASH,
-    AnthropicModels.CLAUDE_3_5_HAIKU,
+    AnthropicModels.CLAUDE_4_5_HAIKU,
   ],

(Exact placement can follow your product positioning, but some inclusion will make the new model discoverable.)

Also applies to: 461-512

CLAUDE.md (1)

296-297: Minor: Consider adding type file location constraint.

Based on learnings, all new type definitions must be placed in src/lib/types/. Consider adding this constraint to the "Adding a New Provider" section to ensure consistency.

 6. Update vision capabilities in `src/lib/adapters/providerImageAdapter.ts` if multimodal
+6a. Place any new type definitions in `src/lib/types/`
 7. Add to CLI choices in `src/cli/factories/commandFactory.ts`
docs/reference/provider-feature-compatibility.md (1)

455-455: Nitpick: Minor redundancy in wording.

"CLI interface" is redundant since CLI stands for "Command Line Interface". Consider simplifying.

-18. CLI Business Tools - Custom tools via CLI interface
+18. CLI Business Tools - Custom tools via CLI
test/run-all-providers-sequential.sh (1)

64-64: Unused variable PROVIDER_START.

The variable PROVIDER_START is assigned but never used. Either remove it or use it to calculate per-provider duration.

   LOG_FILE="$LOG_DIR/test-$provider.log"
-  PROVIDER_START=$(date +%s)
 
   # Run test and capture output

Alternatively, if per-provider timing is desired:

   LOG_FILE="$LOG_DIR/test-$provider.log"
   PROVIDER_START=$(date +%s)
 
   # Run test and capture output
   if npx tsx test/continuous-test-suite.ts --provider "$provider" 2>&1 | tee "$LOG_FILE"; then
+    PROVIDER_END=$(date +%s)
+    PROVIDER_DURATION=$((PROVIDER_END - PROVIDER_START))
     PASS_RATE=$(extract_pass_rate "$LOG_FILE")
     DURATION=$(extract_duration "$LOG_FILE")
-    echo "✅ $provider: $PASS_RATE (${DURATION}s)" | tee -a "$RESULTS_FILE"
+    echo "✅ $provider: $PASS_RATE (${PROVIDER_DURATION}s wall clock)" | tee -a "$RESULTS_FILE"
src/lib/core/modules/MessageBuilder.ts (1)

42-96: Factor out shared multimodal detection and CoreMessage conversion helpers

Both buildMessages and buildMessagesForStream duplicate hasMultimodalInput and the messages.map(...) conversion to CoreMessage. Keeping these in sync across two methods plus any future callers (or additional multimodal dimensions) will be error‑prone.

Consider extracting:

  • a private hasMultimodalInput(input?: MultimodalInput): boolean, and
  • a private toCoreMessages(messages: { role: string; content: unknown }[]): CoreMessage[]

and then reusing them in both methods. This keeps multimodal routing and CoreMessage shaping consistent and reduces maintenance surface if MultimodalInput or content variants evolve later.

Also applies to: 128-190

src/lib/adapters/providerImageAdapter.ts (1)

8-8: Multimodal Content import and vision capability expansions look good, with a couple of optional cleanups

Switching Content to ../types/multimodal.js keeps convertToContent aligned with the centralized multimodal union, and the expanded VISION_CAPABILITIES sets (Anthropic/Vertex/Mistral/Bedrock) cover a broad range of likely model IDs/aliases.

Two optional points to consider:

  • The Vertex list now contains duplicate entries for some Claude Haiku 4.5 variants (e.g., claude-haiku-4-5 appears more than once); deduplicating would reduce noise without changing behavior.
  • The Bedrock list’s generic "anthropic.claude" prefix will mark all Anthropic Bedrock models as vision‑capable; if you still support legacy non‑vision Claude variants, you may want to narrow this to the specific 3.x/4.x families instead of the entire prefix.

Also applies to: 58-115, 130-205

src/lib/utils/pdfProcessor.ts (1)

6-9: PDF→image pipeline is solid; consider also cleaning up the loading task on early failure

The new pdfjs/canvas‑based convertPDFToImages implementation, plus mistral.supportsNative = false and the improved “configured providers” error message, all look correct and align with the goal of falling back to image conversion when native PDF support isn’t available. Destroying pdfDocument in the finally block is a good fix for the earlier leak concern.

One remaining robustness tweak: if pdfjs.getDocument() fails before loadingTask.promise resolves (so pdfDocument never gets assigned), the loading task itself is never explicitly destroyed. To fully mirror pdfjs‑dist’s recommended cleanup, you could keep a loadingTask variable and call loadingTask.destroy() in finally when pdfDocument is still null.

Also applies to: 96-103, 136-146, 240-332

src/lib/providers/ollama.ts (1)

1063-1067: Multimodal content silently converted to text-only in OpenAI-compatible mode.

When multimodal input is detected in OpenAI-compatible mode, the code extracts only the text content and discards image data. This could lead to unexpected behavior where users provide images but they're silently ignored.

Consider logging a warning when images are provided but cannot be used in OpenAI-compatible mode:

         // Convert multimodal messages to text (OpenAI-compatible mode doesn't support images in /v1/chat/completions for Ollama)
+        if (multimodalMessages.some(msg => Array.isArray(msg.content) && msg.content.some(c => c.type === 'image'))) {
+          logger.warn('Ollama OpenAI-compatible mode does not support images; image content will be ignored');
+        }
         const content = multimodalMessages
           .map((msg) => (typeof msg.content === "string" ? msg.content : ""))
           .join("\n");
src/lib/core/baseProvider.ts (1)

716-721: Cost calculation delegated to TelemetryHandler but method is private.

The calculateActualCost method is declared private but only called from recordPerformanceMetrics which also delegates to TelemetryHandler. This creates a redundant delegation chain. Consider removing this private method since TelemetryHandler already encapsulates cost calculation internally.

src/lib/core/modules/StreamHandler.ts (1)

136-154: validateStreamOptionsOnly may have incomplete multimodal validation.

The validation allows either text or images to be present, but doesn't validate other multimodal input types like content, files, csvFiles, or pdfFiles that are supported by StreamOptions. If any of these are provided without text/images, validation will fail incorrectly.

Consider expanding the check:

-    if (!options.input.text && !options.input.images?.length) {
+    if (!options.input.text && 
+        !options.input.images?.length && 
+        !options.input.content?.length &&
+        !options.input.files?.length) {
       throw new ValidationError(
-        "Stream input must include either text or images",
+        "Stream input must include text, images, content, or files",
         "input",
         "MISSING_REQUIRED",
-        ["Provide options.input.text or options.input.images"],
+        ["Provide options.input.text, options.input.images, options.input.content, or options.input.files"],
       );
     }
src/lib/core/modules/TelemetryHandler.ts (1)

229-235: Session and user ID extraction uses unsafe type assertions.

The extraction logic for sessionId and userId casts options to multiple types. This could be simplified by checking the property existence more safely:

     const sessionId =
-      (options.context?.sessionId as string) ||
-      (options as unknown as { sessionId?: string }).sessionId ||
+      (typeof options.context?.sessionId === 'string' ? options.context.sessionId : undefined) ||
+      ('sessionId' in options && typeof options.sessionId === 'string' ? options.sessionId : undefined) ||
       `session-${nanoid()}`;

The current implementation works but is harder to reason about.

src/lib/providers/litellm.ts (1)

169-169: chunkCount variable declared but only used for logging.

The chunkCount is incremented in onChunk and logged in error/finish handlers, but not included in the returned result's metadata. If this metric is useful for debugging, consider including it in the response:

         metadata: {
           startTime,
           streamId: `litellm-${Date.now()}`,
+          totalChunks: chunkCount,
         },
src/lib/core/modules/Utilities.ts (3)

237-250: Consider edge case: numeric strings without units fall through to default.

If a user passes timeout: "30000" (a numeric string without a unit), it will return defaultTimeout instead of 30000ms. This behavior differs from when timeout: 30000 (number) is passed.

If this is intentional, consider adding a comment. Otherwise:

     // Parse string timeout (e.g., '30s', '2m', '1h')
     const timeoutStr = options.timeout.toLowerCase();
     const value = parseInt(timeoutStr);
 
     if (timeoutStr.includes("h")) {
       return value * 60 * 60 * 1000;
     } else if (timeoutStr.includes("m")) {
       return value * 60 * 1000;
     } else if (timeoutStr.includes("s")) {
       return value * 1000;
+    } else if (!isNaN(value)) {
+      // Numeric string without unit, treat as milliseconds
+      return value;
     }
 
     return this.defaultTimeout;

255-262: Duck-typing heuristic is reasonable but could be more specific.

The comment mentions _def but the code only checks for parse. This could match non-Zod objects with a parse method. Consider adding the _def check mentioned in the comment for better accuracy:

   isZodSchema(schema: unknown): boolean {
     return (
       typeof schema === "object" &&
       schema !== null &&
-      // Most Zod schemas have an internal _def and a parse method
-      typeof (schema as { parse?: unknown }).parse === "function"
+      // Zod schemas have an internal _def and a parse method
+      "_def" in schema &&
+      typeof (schema as { parse?: unknown }).parse === "function"
     );
   }

423-446: Consider case-insensitive matching for error messages.

The string comparisons are case-sensitive, but error messages from different providers may vary in capitalization. For example, "Unauthorized" vs "unauthorized":

-    const message = error instanceof Error ? error.message : String(error);
+    const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
 
     // Common API key errors
     if (
-      message.includes("API_KEY_INVALID") ||
-      message.includes("Invalid API key") ||
+      message.includes("api_key_invalid") ||
+      message.includes("invalid api key") ||
       message.includes("authentication") ||
       message.includes("unauthorized")
     ) {
src/lib/core/modules/ToolsManager.ts (7)

108-134: Document tool precedence order.

The method processes tools in a specific order (direct → custom → external MCP → MCP), and later processing methods use !tools[name] checks to avoid overwriting. This implements an implicit precedence: direct tools always win. Consider adding a comment explicitly documenting this precedence rule.

Add clarifying comment:

   async getAllTools(): Promise<Record<string, Tool>> {
+    // Tool precedence: Direct tools > Custom tools > External MCP > MCP tools
+    // Tools added first take precedence; later tools won't overwrite existing names
     // Start with wrapped direct tools that emit events
     const tools: Record<string, Tool> = {};

169-248: Simplify type guard logic.

The type guard checking for directTool && typeof directTool === "object" && "execute" in directTool is repeated on Lines 183-186 after being checked on Lines 172-179. Consider extracting to a helper or restructuring.

Apply this refactor:

     for (const [toolName, directTool] of Object.entries(this.directTools)) {
-      logger.debug(`Processing direct tool: ${toolName}`, {
-        toolName,
-        hasExecute:
-          directTool &&
-          typeof directTool === "object" &&
-          "execute" in directTool,
-        hasDescription:
-          directTool &&
-          typeof directTool === "object" &&
-          "description" in directTool,
-      });
-
-      // Wrap the direct tool's execute function with event emission
-      if (
+      const hasExecute =
         directTool &&
         typeof directTool === "object" &&
-        "execute" in directTool
-      ) {
+        "execute" in directTool;
+      
+      logger.debug(`Processing direct tool: ${toolName}`, {
+        toolName,
+        hasExecute,
+        hasDescription:
+          directTool &&
+          typeof directTool === "object" &&
+          "description" in directTool,
+      });
+
+      // Wrap the direct tool's execute function with event emission
+      if (hasExecute) {
         const originalExecute = (
           directTool as { execute: (params: unknown) => Promise<unknown> }
         ).execute;

392-418: Complex schema resolution logic.

The schema prioritization has four conditional branches checking different combinations of parameters vs inputSchema and Zod vs JSON Schema. Consider extracting this to a helper method for clarity and testing.

Example refactor:

private resolveToolSchema(
  parameters: unknown,
  inputSchema: unknown,
): z.ZodSchema | ReturnType<typeof jsonSchema> {
  // Prioritize parameters (Zod), then inputSchema (Zod or JSON Schema)
  if (parameters && this.utilities?.isZodSchema?.(parameters)) {
    return parameters as z.ZodSchema;
  } else if (inputSchema && this.utilities?.isZodSchema?.(inputSchema)) {
    return inputSchema as z.ZodSchema;
  } else if (inputSchema && typeof inputSchema === "object") {
    return jsonSchema(inputSchema as Record<string, unknown>);
  } else if (parameters && typeof parameters === "object") {
    return convertJsonSchemaToZod(parameters as Record<string, unknown>);
  } else {
    return z.object({});
  }
}

Then simplify Line 392-418 to:

const finalSchema = this.resolveToolSchema(toolInfo.parameters, toolInfo.inputSchema);

446-474: Consider reducing logging verbosity in production.

The parameter flow tracing (lines 446-474) spans ~30 lines and logs extensive object inspection. While useful for debugging, consider wrapping in a conditional based on log level or feature flag to reduce noise in production.


569-581: Duplicated schema handling logic.

The schema handling pattern here (Lines 569-581) is similar to the logic in createCustomToolFromDefinition (Lines 392-418). Both check for JSON Schema, apply fixes for OpenAI strict mode, and fall back to permissive schemas. Consider extracting to a shared helper to reduce duplication.

Example:

private resolveExternalToolSchema(
  inputSchema?: StandardRecord,
): z.ZodSchema | ReturnType<typeof jsonSchema> {
  if (inputSchema && typeof inputSchema === "object") {
    const fixedSchema = this.utilities?.fixSchemaForOpenAIStrictMode
      ? this.utilities.fixSchemaForOpenAIStrictMode(inputSchema as Record<string, unknown>)
      : inputSchema;
    return jsonSchema(fixedSchema);
  } else {
    return this.utilities?.createPermissiveZodSchema
      ? this.utilities.createPermissiveZodSchema()
      : z.object({});
  }
}

196-222: Two different event emission patterns used.

The code uses two event emission approaches:

  1. Direct/External MCP tools (Lines 196-222, 599-608): neurolink.getEventEmitter().emit("tool:start", ...)
  2. Custom tools (Lines 427-442): neurolink.emitToolStart(...)

Both emit Bedrock-compatible events, but the inconsistency could be confusing. If this is intentional (e.g., custom tools need executionId tracking), consider adding comments explaining when to use each pattern.

Also applies to: 427-442


277-279: Complex type assertion with fallback.

Lines 277-279 use a complex pattern: (toolDef as Record<string, unknown> | undefined) || ({} as Record<string, unknown>). This creates a fallback empty object if toolDef is falsy, but the assertion bypasses type checking. Consider simplifying or adding runtime validation.

Simplify:

-      const toolInfo =
-        (toolDef as Record<string, unknown> | undefined) ||
-        ({} as Record<string, unknown>);
+      const toolInfo = toolDef && typeof toolDef === "object" 
+        ? toolDef as Record<string, unknown>
+        : {};
       if (toolInfo && typeof toolInfo.execute === "function") {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63b3e43 and feb411f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (61)
  • CLAUDE.md (1 hunks)
  • CODE_QUALITY_FIXES.md (1 hunks)
  • COMMIT_ANALYSIS_REPORT.md (1 hunks)
  • HAYSTACK_MULTIMODAL_ANALYSIS.md (1 hunks)
  • MULTIMODALITY_GAP_ANALYSIS.md (1 hunks)
  • MULTIMODAL_IMPLEMENTATION_GUIDE.md (1 hunks)
  • OLLAMA_FIX_SUMMARY.md (1 hunks)
  • OLLAMA_TEST_VERIFICATION.md (1 hunks)
  • PR_COMMENTS_IMPACT_ANALYSIS.md (1 hunks)
  • PR_COMMENTS_SOLUTION_PLAN.md (1 hunks)
  • PR_REVIEW_FIXES_SUMMARY.md (1 hunks)
  • README.md (1 hunks)
  • SDK_STREAM_BUG_FIX_SUMMARY.md (1 hunks)
  • docs/getting-started/API-REFERENCE.md (0 hunks)
  • docs/getting-started/provider-setup.md (0 hunks)
  • docs/reference/provider-feature-compatibility.md (1 hunks)
  • docs/sdk/api-reference.md (0 hunks)
  • package.json (3 hunks)
  • scripts/env-validation.cjs (21 hunks)
  • src/cli/factories/commandFactory.ts (1 hunks)
  • src/lib/adapters/providerImageAdapter.ts (6 hunks)
  • src/lib/agent/directTools.ts (1 hunks)
  • src/lib/constants/enums.ts (1 hunks)
  • src/lib/constants/tokens.ts (3 hunks)
  • src/lib/core/baseProvider.ts (11 hunks)
  • src/lib/core/constants.ts (2 hunks)
  • src/lib/core/modelConfiguration.ts (1 hunks)
  • src/lib/core/modules/GenerationHandler.ts (1 hunks)
  • src/lib/core/modules/MessageBuilder.ts (1 hunks)
  • src/lib/core/modules/StreamHandler.ts (1 hunks)
  • src/lib/core/modules/TelemetryHandler.ts (1 hunks)
  • src/lib/core/modules/ToolsManager.ts (1 hunks)
  • src/lib/core/modules/Utilities.ts (1 hunks)
  • src/lib/factories/providerRegistry.ts (1 hunks)
  • src/lib/mcp/servers/agent/directToolsServer.ts (0 hunks)
  • src/lib/models/modelRegistry.ts (1 hunks)
  • src/lib/neurolink.ts (4 hunks)
  • src/lib/providers/amazonBedrock.ts (3 hunks)
  • src/lib/providers/anthropic.ts (1 hunks)
  • src/lib/providers/azureOpenai.ts (1 hunks)
  • src/lib/providers/googleAiStudio.ts (1 hunks)
  • src/lib/providers/googleVertex.ts (1 hunks)
  • src/lib/providers/huggingFace.ts (1 hunks)
  • src/lib/providers/litellm.ts (5 hunks)
  • src/lib/providers/mistral.ts (2 hunks)
  • src/lib/providers/ollama.ts (9 hunks)
  • src/lib/providers/openAI.ts (1 hunks)
  • src/lib/providers/openaiCompatible.ts (1 hunks)
  • src/lib/types/content.ts (1 hunks)
  • src/lib/types/conversation.ts (1 hunks)
  • src/lib/types/generateTypes.ts (2 hunks)
  • src/lib/types/index.ts (1 hunks)
  • src/lib/types/multimodal.ts (1 hunks)
  • src/lib/types/streamTypes.ts (3 hunks)
  • src/lib/utils/imageProcessor.ts (1 hunks)
  • src/lib/utils/messageBuilder.ts (4 hunks)
  • src/lib/utils/pdfProcessor.ts (4 hunks)
  • test/TESTING_SCRIPTS.md (1 hunks)
  • test/continuous-test-suite.ts (10 hunks)
  • test/run-all-providers-sequential.sh (1 hunks)
  • test/test-all-providers.sh (1 hunks)
💤 Files with no reviewable changes (4)
  • docs/getting-started/API-REFERENCE.md
  • docs/getting-started/provider-setup.md
  • src/lib/mcp/servers/agent/directToolsServer.ts
  • docs/sdk/api-reference.md
🧰 Additional context used
🧠 Learnings (18)
📚 Learning: 2025-09-17T17:55:15.261Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 173
File: src/lib/index.ts:16-16
Timestamp: 2025-09-17T17:55:15.261Z
Learning: In src/lib/types/providers.ts, ProviderConfig was renamed to AIModelProviderConfig to deduplicate type names, as there was an existing ProviderConfig type that better suited the "ProviderConfig" name. This was an intentional breaking change for better type organization.

Applied to files:

  • src/lib/factories/providerRegistry.ts
  • src/lib/utils/imageProcessor.ts
  • src/lib/providers/openAI.ts
  • src/lib/core/modelConfiguration.ts
  • src/lib/providers/googleVertex.ts
  • src/lib/providers/azureOpenai.ts
  • src/lib/providers/anthropic.ts
  • src/lib/core/modules/MessageBuilder.ts
  • src/lib/types/conversation.ts
  • src/lib/types/index.ts
  • docs/reference/provider-feature-compatibility.md
  • src/cli/factories/commandFactory.ts
  • src/lib/providers/huggingFace.ts
  • src/lib/providers/googleAiStudio.ts
  • src/lib/models/modelRegistry.ts
  • src/lib/types/generateTypes.ts
  • src/lib/core/baseProvider.ts
  • src/lib/types/streamTypes.ts
  • src/lib/providers/openaiCompatible.ts
  • src/lib/utils/messageBuilder.ts
  • src/lib/core/constants.ts
  • src/lib/adapters/providerImageAdapter.ts
  • src/lib/core/modules/TelemetryHandler.ts
  • src/lib/providers/mistral.ts
  • src/lib/types/content.ts
  • src/lib/core/modules/GenerationHandler.ts
  • src/lib/core/modules/ToolsManager.ts
  • src/lib/types/multimodal.ts
  • src/lib/providers/litellm.ts
  • src/lib/providers/ollama.ts
  • README.md
📚 Learning: 2025-09-02T13:50:42.770Z
Learnt from: YasmeenOgo
Repo: juspay/neurolink PR: 145
File: src/lib/core/types.ts:0-0
Timestamp: 2025-09-02T13:50:42.770Z
Learning: The APIVersions enum in src/lib/core/types.ts now contains comprehensive API version constants for all major AI providers: Azure OpenAI (latest, stable, legacy), OpenAI (current, beta), Google AI (current, beta), and Anthropic (current). This centralization helps avoid API version drift across the codebase.

Applied to files:

  • src/lib/factories/providerRegistry.ts
  • src/lib/providers/azureOpenai.ts
  • src/lib/types/index.ts
  • src/lib/constants/enums.ts
  • src/lib/providers/googleAiStudio.ts
  • src/lib/models/modelRegistry.ts
  • src/lib/providers/openaiCompatible.ts
  • src/lib/core/constants.ts
  • src/lib/providers/litellm.ts
  • src/lib/providers/ollama.ts
  • README.md
📚 Learning: 2025-09-17T18:14:34.960Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 173
File: src/lib/types/index.ts:58-62
Timestamp: 2025-09-17T18:14:34.960Z
Learning: RajuSudhar explained that in the Neurolink codebase, there are multiple ProviderConfig types causing inconsistency. One existing ProviderConfig type better suited the "ProviderConfig" name, so they renamed the less-suitable one to AIModelProviderConfig to free up the name. Adding backward compatibility aliases would worsen naming inconsistency rather than help. The remaining duplicates will be systematically deduplicated in the 07-Types-Module.md TODO as part of their phased refactor approach.

Applied to files:

  • src/lib/factories/providerRegistry.ts
  • src/lib/providers/openAI.ts
  • src/lib/core/modelConfiguration.ts
  • src/lib/providers/azureOpenai.ts
  • src/lib/providers/anthropic.ts
  • MULTIMODAL_IMPLEMENTATION_GUIDE.md
  • src/lib/providers/openaiCompatible.ts
  • CLAUDE.md
  • src/lib/adapters/providerImageAdapter.ts
  • README.md
📚 Learning: 2025-09-01T22:58:39.149Z
Learnt from: sudharsan-juspay
Repo: juspay/neurolink PR: 140
File: src/lib/core/types.ts:198-203
Timestamp: 2025-09-01T22:58:39.149Z
Learning: In src/lib/core/types.ts, StreamOptions (imported from streamTypes.js) and StreamingOptions are intentionally different types with different use cases. StreamingOptions is for unified AI requests with multiple provider configurations, while StreamOptions is for individual streaming operations.

Applied to files:

  • src/lib/providers/googleVertex.ts
  • src/lib/providers/azureOpenai.ts
  • src/lib/providers/huggingFace.ts
  • src/lib/providers/googleAiStudio.ts
  • src/lib/types/generateTypes.ts
  • src/lib/types/streamTypes.ts
  • src/lib/utils/messageBuilder.ts
  • src/lib/neurolink.ts
  • src/lib/core/modules/StreamHandler.ts
  • src/lib/providers/litellm.ts
📚 Learning: 2025-09-24T06:42:06.088Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 185
File: src/lib/evaluation/contextBuilder.ts:79-85
Timestamp: 2025-09-24T06:42:06.088Z
Learning: In the NeuroLink codebase, using `(options.prompt || [])` pattern for handling potentially undefined prompt arrays is the preferred approach over extracting to a normalized variable when building conversation history in the ContextBuilder class.

Applied to files:

  • src/lib/core/modules/MessageBuilder.ts
  • src/lib/providers/amazonBedrock.ts
  • src/lib/utils/messageBuilder.ts
  • src/lib/neurolink.ts
  • src/lib/providers/ollama.ts
📚 Learning: 2025-09-24T07:26:41.988Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 185
File: src/lib/evaluation/prompts.ts:86-101
Timestamp: 2025-09-24T07:26:41.988Z
Learning: In the neurolink codebase, maintainer amreetkhuntia consistently prefers to keep template literal indentation in LLM prompts (including evaluation prompts in src/lib/evaluation/prompts.ts) for readability, even when it results in extra whitespace in the output, as LLMs can parse and understand the content correctly.

Applied to files:

  • src/lib/core/modules/MessageBuilder.ts
📚 Learning: 2025-09-24T06:41:27.575Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 185
File: src/lib/evaluation/contextBuilder.ts:53-63
Timestamp: 2025-09-24T06:41:27.575Z
Learning: In the NeuroLink codebase, `LanguageModelV1CallOptions.prompt` is always present and never undefined, so defensive checks are not needed when accessing this property.

Applied to files:

  • src/lib/core/modules/MessageBuilder.ts
  • src/lib/providers/ollama.ts
📚 Learning: 2025-09-28T21:00:08.243Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 174
File: src/lib/mcp/contracts/mcpContract.ts:0-0
Timestamp: 2025-09-28T21:00:08.243Z
Learning: The src/lib/mcp/contracts/mcpContract.ts file was completely removed during the MCP types refactor in PR #174, with its types moved to centralized modules like src/lib/types/mcpTypes.ts and src/lib/types/index.ts.

Applied to files:

  • src/lib/types/conversation.ts
📚 Learning: 2025-11-05T20:31:04.103Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 227
File: src/lib/utils/redis.ts:15-15
Timestamp: 2025-11-05T20:31:04.103Z
Learning: In the juspay/neurolink repository, type centralization rules (requiring types in src/lib/types/) do not apply to private, non-exported utility types used within a single file. Simple readability helpers like `type RedisClient = ReturnType<typeof createClient>` should remain in their implementation file when they are not exported and only used locally. Only exported types shared across modules, business/domain types, and public API types require centralization.

Applied to files:

  • src/lib/types/index.ts
  • src/lib/types/content.ts
📚 Learning: 2025-09-01T06:15:59.759Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 133
File: src/lib/core/types.ts:208-210
Timestamp: 2025-09-01T06:15:59.759Z
Learning: The middleware?: MiddlewareFactoryOptions field is already present in both TextGenerationOptions and StreamOptions interfaces in the neurolink codebase.

Applied to files:

  • src/lib/types/generateTypes.ts
  • src/lib/utils/messageBuilder.ts
📚 Learning: 2025-09-01T14:12:14.227Z
Learnt from: swaroopvarma1
Repo: juspay/neurolink PR: 141
File: docs/REAL-TIME-SPEECH-AGENTS.md:124-149
Timestamp: 2025-09-01T14:12:14.227Z
Learning: In the NeuroLink Speech-to-Speech agent system, the team prefers simple void-returning APIs (sendAudioFrame, sendText, flush) over Promise-based backpressure mechanisms, prioritizing ease of use and implementation simplicity for real-time speech processing.

Applied to files:

  • MULTIMODAL_IMPLEMENTATION_GUIDE.md
📚 Learning: 2025-11-17T13:53:20.209Z
Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 237
File: memory-bank/tts-provider-implementation-plan.md:92-106
Timestamp: 2025-11-17T13:53:20.209Z
Learning: In PR 237's TTS modality implementation approach, TTS functionality uses GOOGLE_AI_API_KEY (not GOOGLE_TTS_API_KEY) when using the google-ai provider. TTS is implemented as an output modality that leverages the existing google-ai provider authentication.

Applied to files:

  • MULTIMODAL_IMPLEMENTATION_GUIDE.md
📚 Learning: 2025-11-04T22:14:18.719Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-11-04T22:14:18.719Z
Learning: In the juspay/neurolink repository, all new type definitions must be placed in src/lib/types/. New type definitions outside this directory should be flagged and blocked in code reviews.

Applied to files:

  • CLAUDE.md
  • src/lib/types/multimodal.ts
📚 Learning: 2025-09-10T08:22:11.910Z
Learnt from: sudharsan-juspay
Repo: juspay/neurolink PR: 160
File: src/lib/providers/index.ts:43-44
Timestamp: 2025-09-10T08:22:11.910Z
Learning: In the Neurolink project, type deduplication across modules (like ProviderName definitions) should be handled as separate tasks rather than mixed with other refactoring efforts, as there are multiple such occurrences throughout the codebase that need systematic cleanup.

Applied to files:

  • src/lib/core/modules/TelemetryHandler.ts
  • MULTIMODALITY_GAP_ANALYSIS.md
📚 Learning: 2025-11-04T22:14:18.719Z
Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-11-04T22:14:18.719Z
Learning: In the juspay/neurolink repository, do not flag existing type or interface definitions located outside src/lib/types/ - these are part of a phased migration plan and will be addressed in upcoming PRs. Only enforce type centralization rules on new code going forward.

Applied to files:

  • src/lib/types/content.ts
📚 Learning: 2025-09-07T09:14:50.565Z
Learnt from: Yaswanth-2874
Repo: juspay/neurolink PR: 149
File: test/conversation-memory-test.js:66-69
Timestamp: 2025-09-07T09:14:50.565Z
Learning: In the juspay/neurolink repository, test files don't need defensive type guards for known API contracts. The user prefers to keep test code simpler without additional safety checks when the data structure is guaranteed.

Applied to files:

  • test/continuous-test-suite.ts
📚 Learning: 2025-10-01T07:58:00.270Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 197
File: neurolink-demo/middleware/guardrails-precall-demo.ts:123-145
Timestamp: 2025-10-01T07:58:00.270Z
Learning: Demo files in the neurolink-demo/ directory can be ignored and should not be subject to detailed code review scrutiny.

Applied to files:

  • MULTIMODALITY_GAP_ANALYSIS.md
📚 Learning: 2025-10-01T07:57:56.458Z
Learnt from: amreetkhuntia
Repo: juspay/neurolink PR: 197
File: neurolink-demo/middleware/guardrails-precall-demo.ts:112-118
Timestamp: 2025-10-01T07:57:56.458Z
Learning: Demo files in the neurolink-demo directory should be ignored during code reviews, as they are for demonstration purposes only.

Applied to files:

  • MULTIMODALITY_GAP_ANALYSIS.md
🧬 Code graph analysis (13)
src/lib/core/modules/MessageBuilder.ts (5)
src/lib/types/index.ts (2)
  • AIProviderName (9-9)
  • StreamOptions (181-181)
src/lib/types/generateTypes.ts (1)
  • TextGenerationOptions (183-228)
src/lib/types/content.ts (1)
  • MultimodalInput (27-27)
src/lib/types/multimodal.ts (1)
  • MultimodalInput (209-222)
src/lib/types/streamTypes.ts (1)
  • StreamOptions (156-233)
src/lib/models/modelRegistry.ts (2)
src/lib/types/index.ts (1)
  • AIProviderName (9-9)
src/lib/index.ts (1)
  • AIProviderName (38-38)
src/lib/providers/amazonBedrock.ts (6)
src/lib/types/index.ts (1)
  • StreamOptions (181-181)
src/lib/types/streamTypes.ts (1)
  • StreamOptions (156-233)
src/lib/utils/multimodalOptionsBuilder.ts (1)
  • buildMultimodalOptions (45-70)
src/lib/utils/messageBuilder.ts (1)
  • buildMultimodalMessagesArray (436-728)
src/lib/types/providers.ts (1)
  • BedrockMessage (482-485)
scripts/env-validation.cjs (1)
  • path (15-15)
src/lib/types/generateTypes.ts (1)
src/lib/types/multimodal.ts (1)
  • Content (193-199)
src/lib/core/baseProvider.ts (6)
src/lib/core/modules/MessageBuilder.ts (1)
  • MessageBuilder (32-214)
src/lib/core/modules/StreamHandler.ts (1)
  • StreamHandler (32-155)
src/lib/core/modules/GenerationHandler.ts (1)
  • GenerationHandler (34-313)
src/lib/core/modules/TelemetryHandler.ts (1)
  • TelemetryHandler (37-259)
src/lib/core/modules/Utilities.ts (1)
  • Utilities (42-450)
src/lib/core/modules/ToolsManager.ts (1)
  • ToolsManager (47-709)
src/lib/types/streamTypes.ts (1)
src/lib/types/multimodal.ts (1)
  • Content (193-199)
src/lib/core/modules/Utilities.ts (6)
src/lib/types/generateTypes.ts (1)
  • TextGenerationOptions (183-228)
src/lib/utils/parameterValidation.ts (3)
  • validateTextGenerationOptions (385-474)
  • createValidationSummary (716-734)
  • ValidationError (29-46)
src/lib/core/constants.ts (1)
  • STEP_LIMITS (13-17)
src/lib/types/streamTypes.ts (1)
  • StreamOptions (156-233)
src/lib/utils/tokenLimits.ts (1)
  • getSafeMaxTokens (12-60)
src/lib/utils/timeout.ts (1)
  • TimeoutError (13-27)
src/lib/providers/mistral.ts (2)
src/lib/utils/providerConfig.ts (1)
  • getProviderModel (178-180)
tools/automation/buildSystem.js (1)
  • options (432-437)
src/lib/core/modules/GenerationHandler.ts (5)
src/lib/types/index.ts (5)
  • AIProviderName (9-9)
  • StandardRecord (16-16)
  • UnknownRecord (50-50)
  • ToolResult (63-63)
  • ToolResult (178-178)
src/lib/types/generateTypes.ts (2)
  • TextGenerationOptions (183-228)
  • EnhancedGenerateResult (261-264)
src/lib/core/baseProvider.ts (1)
  • generateText (522-560)
src/lib/types/providers.ts (2)
  • AISDKGenerateResult (410-420)
  • ExtendedTool (405-405)
src/lib/types/streamTypes.ts (1)
  • ToolResult (77-91)
src/lib/neurolink.ts (1)
src/lib/core/modelConfiguration.ts (2)
  • modelConfig (1088-1088)
  • ModelConfigurationManager (97-1083)
src/lib/core/modules/StreamHandler.ts (3)
src/lib/types/streamTypes.ts (2)
  • StreamOptions (156-233)
  • StreamResult (239-280)
src/lib/utils/parameterValidation.ts (2)
  • createValidationSummary (716-734)
  • ValidationError (29-46)
src/lib/core/constants.ts (1)
  • STEP_LIMITS (13-17)
src/lib/providers/litellm.ts (3)
src/lib/types/index.ts (1)
  • StreamResult (183-183)
src/lib/types/sdkTypes.ts (1)
  • StreamResult (11-11)
src/lib/core/constants.ts (1)
  • DEFAULT_MAX_STEPS (10-10)
src/lib/providers/ollama.ts (3)
src/lib/utils/logger.ts (2)
  • logger (358-401)
  • error (239-241)
src/lib/utils/multimodalOptionsBuilder.ts (1)
  • buildMultimodalOptions (45-70)
src/lib/utils/messageBuilder.ts (1)
  • buildMultimodalMessagesArray (436-728)
🪛 LanguageTool
PR_COMMENTS_SOLUTION_PLAN.md

[uncategorized] ~311-~311: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...ent - Risk: Low - Widening type is backward compatible - Impact: Medium - Enables proper m...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[uncategorized] ~698-~698: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...ocumentation (Low Priority) 📚 11. Fix markdown tables - 1 min 12. Remove local pat...

(MARKDOWN_NNP)

docs/reference/provider-feature-compatibility.md

[style] ~455-~455: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: .... CLI Business Tools - Custom tools via CLI interface #### Enterprise Features Tests (1 test...

(ACRONYM_TAUTOLOGY)

HAYSTACK_MULTIMODAL_ANALYSIS.md

[grammar] ~687-~687: Ensure spelling is correct
Context: ...** (cost/privacy flexibility) ### What NeuroLink Does Better 1. **Vision model integrat...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

CODE_QUALITY_FIXES.md

[grammar] ~50-~50: Use a hyphen to join words.
Context: ...(line 154) ### Problem The two message building methods had inconsistent fallba...

(QB_NEW_EN_HYPHEN)


[grammar] ~77-~77: Use a hyphen to join words.
Context: ...tilized as a fallback across all message building operations - **Backward Compati...

(QB_NEW_EN_HYPHEN)

MULTIMODAL_IMPLEMENTATION_GUIDE.md

[style] ~117-~117: Consider a different adjective to strengthen your wording.
Context: ...## Current Architecture Problems After deep analysis of the actual codebase impleme...

(DEEP_PROFOUND)


[style] ~172-~172: To elevate your writing, try using a synonym here.
Context: ...enance burden, difficult to understand, hard to extend ### Solution Architecture #...

(HARD_TO)


[uncategorized] ~1076-~1076: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...Pattern: Upload → Transcribe → Store as markdown with header Dependencies to Add: ...

(MARKDOWN_NNP)


[style] ~2034-~2034: Consider using a different verb for a more formal wording.
Context: ...lease Preparation - [ ] Run linter and fix issues: npm run lint - [ ] Run type c...

(FIX_RESOLVE)

PR_COMMENTS_IMPACT_ANALYSIS.md

[uncategorized] ~613-~613: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...(Documentation/non-functional) 10. Fix markdown table (Issue #3) 11. Remove local path ...

(MARKDOWN_NNP)


[style] ~624-~624: Consider using a different verb for a more formal wording.
Context: ...ssues:** 4 critical issues that must be fixed before merge Data Integrity Issues:...

(FIX_RESOLVE)

MULTIMODALITY_GAP_ANALYSIS.md

[style] ~40-~40: Consider a different adjective to strengthen your wording.
Context: ...aintainability and extensibility After deep analysis of the actual codebase, **crit...

(DEEP_PROFOUND)


[style] ~719-~719: This adverb was used twice in the sentence. Consider removing one of them or replacing them with a synonym.
Context: ... - ❌ Only PCM streaming - ❌ Gemini Live only (no other providers) - ❌ No audio file ...

(ADVERB_REPETITION_PREMIUM)


[uncategorized] ~770-~770: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...xing After transcription: 1. Store as markdown document 2. Summarize by LLM 3. Chunk f...

(MARKDOWN_NNP)

🪛 Shellcheck (0.11.0)
test/run-all-providers-sequential.sh

[warning] 64-64: PROVIDER_START appears unused. Verify use (or export if used externally).

(SC2034)

Comment thread PR_COMMENTS_IMPACT_ANALYSIS.md Outdated
Comment on lines +550 to +553
} catch (toolCreationError) {
logger.error(`Failed to create tool: ${toolName}`, toolCreationError);
return null;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, find and examine the createCustomToolFromDefinition method and its call sites
ast-grep --pattern $'createCustomToolFromDefinition($$$)'

Repository: juspay/neurolink

Length of output: 42


🏁 Script executed:

# Find the file and check its size
wc -l src/lib/core/modules/ToolsManager.ts

# Search for createCustomToolFromDefinition calls
rg -n 'createCustomToolFromDefinition' src/lib/core/modules/ToolsManager.ts

# Search for processCustomTools
rg -n 'processCustomTools' src/lib/core/modules/ToolsManager.ts

Repository: juspay/neurolink

Length of output: 351


🏁 Script executed:

# Read the processCustomTools method and context around line 281
sed -n '259,295p' src/lib/core/modules/ToolsManager.ts

# Read the createCustomToolFromDefinition method and the error handling around 550-553
sed -n '376,410p' src/lib/core/modules/ToolsManager.ts
sed -n '545,560p' src/lib/core/modules/ToolsManager.ts

Repository: juspay/neurolink

Length of output: 2967


🏁 Script executed:

# Check if there are similar null-return patterns in the codebase
rg -n 'return null' src/lib/core/modules/ToolsManager.ts

# Check for error tracking or logging patterns around tool creation
rg -n 'Failed to create tool' src/lib/core/modules/

# Look for any tests or documentation about tool creation failure handling
fd -e ts -e md | xargs rg -l 'createCustomToolFromDefinition|tool.*fail|tool.*error' -i | head -20

Repository: juspay/neurolink

Length of output: 881


🏁 Script executed:

# Read the other null return at line 706 and its context
sed -n '700,710p' src/lib/core/modules/ToolsManager.ts

# Search for error accumulation or tracking patterns
rg -n -B3 -A3 'logger.error.*tool' src/lib/core/modules/ToolsManager.ts | head -40

# Check if processCustomTools does any error accumulation
sed -n '259,300p' src/lib/core/modules/ToolsManager.ts

Repository: juspay/neurolink

Length of output: 2121


🏁 Script executed:

# Check if there's any documentation or comments about the error handling strategy
rg -n -B5 'return null' src/lib/core/modules/ToolsManager.ts | grep -E '(//|/\*|TODO|FIXME|NOTE)'

# Look for any higher-level error tracking or tool failure accumulation
rg -n 'processCustomTools|createCustomToolFromDefinition' src/lib/core/modules/ToolsManager.ts | head -10

# Check where processCustomTools is called from
rg -n -B3 -A3 'await this.processCustomTools' src/lib/core/modules/ToolsManager.ts

Repository: juspay/neurolink

Length of output: 536


Based on my verification, I can now provide the rewritten review comment:


Intentional null return silently skips failed tools without visibility to callers.

The createCustomToolFromDefinition method returns null on error (lines 550–553), and processCustomTools checks for null to skip failed tools (line 284-285). This is consistent design across both custom and external MCP tool creation methods (see line 706 in createExternalMCPTool). However, errors are only logged; there's no error accumulation or reporting mechanism for callers to determine which or how many tools failed to load. If a tool fails due to misconfiguration or unavailability, the failure is silent to the application. Consider whether higher-level callers need visibility into tool creation failures or if graceful degradation (current behavior) is sufficient.

Comment on lines +667 to +676
// Only disable tools if we have positive evidence the model doesn't support them
// If toolCapableModels config is empty, assume tools are supported (don't make assumptions)
if (toolCapableModels.length === 0) {
logger.debug("Ollama tool calling enabled", {
model: this.modelName,
reason: "No tool-capable config defined, assuming tools supported",
baseUrl: this.baseUrl,
});
return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for configuration documentation and migration guides
echo "=== Checking for docs and configuration files ==="
fd -e md -e txt | head -20

echo -e "\n=== Searching for README or docs about configuration ==="
find . -maxdepth 2 -type f \( -name "README*" -o -name "MIGRATION*" -o -name "CHANGELOG*" \) | head -10

echo -e "\n=== Looking for configuration examples or defaults ==="
rg -n "toolCapableModels" --type=ts --type=json -B 2 -A 2 | head -50

Repository: juspay/neurolink

Length of output: 4283


🏁 Script executed:

#!/bin/bash
# Read the full method context in ollama.ts around the tools logic
echo "=== Full context of supportsToolCalling method ==="
sed -n '630,700p' src/lib/providers/ollama.ts

echo -e "\n=== Check README.md for ollama configuration docs ==="
rg -n "ollama\|tool" README.md -i -B 2 -A 2 | head -80

Repository: juspay/neurolink

Length of output: 2924


🏁 Script executed:

#!/bin/bash
# Look for any migration or configuration guidance
echo "=== Search for migration guides or setup docs ==="
find . -type f -name "*.md" -exec grep -l "migration\|upgrade\|breaking" {} \; 2>/dev/null | head -10

echo -e "\n=== Check if there's a default configuration file or template ==="
find . -type f \( -name "*default*config*" -o -name "*config*template*" \) -o -path "*/config/*" | head -20

echo -e "\n=== Look for tests showing toolCapableModels usage ==="
rg -n "toolCapableModels" --type=ts -B 5 -A 5 | grep -A 10 -B 10 "test\|describe\|it("

Repository: juspay/neurolink

Length of output: 1900


🏁 Script executed:

#!/bin/bash
# Look for test files with supportsTools or tool calling tests
echo "=== Search for test files ==="
find . -type f \( -name "*.test.ts" -o -name "*.spec.ts" \) | grep -i ollama

echo -e "\n=== Look for tests related to tool calling ==="
rg -n "supportsTools\|toolCapableModels" --type=ts | grep -i test

Repository: juspay/neurolink

Length of output: 137


🏁 Script executed:

#!/bin/bash
# Get file sizes first to decide how to read
echo "=== File sizes ==="
wc -l docs/CONFIGURATION.md config/models.json 2>/dev/null

# Read the files
echo -e "\n=== Reading CONFIGURATION.md ==="
cat docs/CONFIGURATION.md

echo -e "\n=== Reading config/models.json ==="
cat config/models.json

Repository: juspay/neurolink

Length of output: 26711


Add documentation for Ollama tool configuration behavior change and the OLLAMA_TOOL_CAPABLE_MODELS configuration option.

The behavior change from explicit opt-in to default-enabled tools when toolCapableModels is empty is documented only in code comments but not in user-facing documentation. CONFIGURATION.md lacks any mention of:

  • The OLLAMA_TOOL_CAPABLE_MODELS environment variable
  • The modelBehavior.toolCapableModels configuration option
  • The default behavior change and its implications

Add to docs/CONFIGURATION.md in the Ollama Configuration section:

### **Tool Calling Configuration**

By default, tools are assumed to be supported for all models when no `toolCapableModels` config is defined.
To explicitly control which models support tools, configure:

```bash
# Comma-separated list of models that support tool calling
export OLLAMA_TOOL_CAPABLE_MODELS="llama3.1:8b-instruct,mistral:7b-instruct"

# Or in configuration file (providers.ollama.modelBehavior.toolCapableModels)

Migration Note: Previous versions required explicit opt-in for tool support. This version assumes tools
are supported by default when no configuration is provided. If tools fail on your model, add the
configuration above to disable them.


<details>
<summary>🤖 Prompt for AI Agents</summary>

In src/lib/providers/ollama.ts around lines 667-676, the code change that
defaults tool-calling to enabled when toolCapableModels is empty is only
documented in code comments; update docs/CONFIGURATION.md (Ollama Configuration
section) to add a "Tool Calling Configuration" subsection that documents the
OLLAMA_TOOL_CAPABLE_MODELS env var, the
providers.ollama.modelBehavior.toolCapableModels config option (comma-separated
model names), explains the new default behavior (tools assumed supported when
not set), and include a short migration note advising users to set the config or
env var to explicitly control/disable tool calling if a model fails.


</details>

<!-- fingerprinting:phantom:medusa:ocelot -->

<!-- This is an auto-generated comment by CodeRabbit -->

Copilot AI review requested due to automatic review settings November 28, 2025 05:22
@murdore
murdore force-pushed the feat/all-multi-modality branch from feb411f to fcf0188 Compare November 28, 2025 05:22
@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 53 out of 54 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

import type { ValidationSchema, StandardRecord } from "./typeAliases.js";
import type { AIModelProviderConfig } from "./providers.js";
import type { TextContent, ImageContent } from "./content.js";
import type { Content } from "./content.js";

Copilot AI Nov 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Content import should come from multimodal.js, not content.js. While content.js appears to re-export from multimodal.js for backward compatibility, using the primary source is preferred for consistency with the architecture refactoring goals.

Copilot uses AI. Check for mistakes.
…oring and enhanced testing

Architecture Refactoring (54% reduction in BaseProvider):
- Extract BaseProvider into 6 SRP-compliant modules (GenerationHandler, MessageBuilder,
  StreamHandler, TelemetryHandler, ToolsManager, Utilities)
- Refactor 11 providers to use composition over inheritance
- Reduce BaseProvider from 2,418 to 1,118 lines

Multimodal Enhancements:
- Add 53 new vision models (GPT-5, Claude 4.x, Llama 4, Gemini 2.0, DeepSeek R1)
- Add AudioContent and VideoContent types with comprehensive JSDoc
- Implement type guards for enhanced type safety
- Expand support across Bedrock, LiteLLM, Mistral, Ollama providers
- Add Claude 4.5 Haiku (claude-haiku-4-5-20251001) model support

Ollama Critical Fixes:
- Fix streaming failures (0 chunks → 100% pass rate)
- Add intelligent tool management (auto-disable for non-capable models)
- Add OpenAI-compatible streaming mode support
- Fix message field handling (options.prompt vs options.messages)
- Add tool capability detection for 8 models

Documentation (5,479 new lines):
- Add CLAUDE.md: Complete architecture guide for AI-assisted development
- Add HAYSTACK_MULTIMODAL_ANALYSIS.md: Comparative analysis (748 lines)
- Add MULTIMODALITY_GAP_ANALYSIS.md: Capability gap analysis (2,165 lines)
- Add MULTIMODAL_IMPLEMENTATION_GUIDE.md: Implementation roadmap (2,184 lines)
- Add provider compatibility matrix (11 providers × 19 features)
- Document SDK stream tool discovery bug fix

Test Infrastructure:
- Add sequential test runner with rate limit protection
- Add smoke test scripts for rapid provider validation
- Add comprehensive testing documentation (TESTING_SCRIPTS.md)
- Fix stream chunk handling for 62 MCP tools
- Add case-insensitive test validation

Code Quality:
- Fix max-params violation (7→4 via ToolUtilities interface)
- Fix max-depth violation in ollama.ts (7→6 via optional chaining)
- Fix pre-commit hook npm test command
- Add type guards for stream chunk processing
- Clean up direct tools and MCP server code
@murdore
murdore force-pushed the feat/all-multi-modality branch from fcf0188 to 50bba69 Compare December 1, 2025 08:36
@github-actions

github-actions Bot commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

@murdore
murdore merged commit fd8d207 into release Dec 1, 2025
12 checks passed
@murdore
murdore deleted the feat/all-multi-modality branch December 1, 2025 08:38
@github-actions

github-actions Bot commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 8.4.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@coderabbitai coderabbitai Bot mentioned this pull request Dec 16, 2025
10 of 43 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants