Skip to content

Conversation

@Scra3
Copy link
Member

@Scra3 Scra3 commented Dec 15, 2025

Summary

  • Add Mistral AI as a new provider option alongside OpenAI
  • Uses @langchain/mistralai for Mistral integration
  • Converts messages between OpenAI and LangChain formats for compatibility
  • Returns responses in OpenAI format for frontend compatibility

Changes

  • Add MistralConfiguration type with provider: 'mistral'
  • Add MistralUnprocessableError for Mistral-specific errors
  • Implement dispatchMistral method in ProviderDispatcher
  • Add message conversion utilities (OpenAI ↔ LangChain)
  • Add comprehensive tests for Mistral provider

Usage

agent.addAI({
  provider: 'mistral',
  model: 'mistral-large-latest',
  apiKey: process.env.MISTRAL_API_KEY,
});

Test plan

  • All existing tests pass
  • New Mistral tests pass
  • Build succeeds
  • Lint passes

🤖 Generated with Claude Code

alban bertolini and others added 2 commits December 15, 2025 13:51
Add support for AI/LLM integration in the agent package.

- New addAI customization method for configuring AI provider
- AI proxy route handler at /_internal/ai-proxy/:route
- Integration with MCP server configuration service
- Schema flag for AI enabled projects

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Update @forestadmin/ai-proxy to 1.0.0 in agent and forestadmin-client
- Add resolution in root package.json to force 1.0.0
- Allow string type for model to support custom models or new versions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@Scra3 Scra3 changed the base branch from main to feat/add-ai-integration December 15, 2025 14:58
@qltysh
Copy link

qltysh bot commented Dec 15, 2025

2 new issues

Tool Category Rule Count
qlty Structure Function with many parameters (count = 4): makeRoutes 1
qlty Structure Function with high complexity (count = 11): dispatch 1

@Scra3 Scra3 force-pushed the feat/ai-proxy-mistral-provider branch 2 times, most recently from a0e7344 to f766cb7 Compare December 15, 2025 15:07
@qltysh
Copy link

qltysh bot commented Dec 15, 2025

Qlty

Coverage Impact

⬆️ Merging this pull request will increase total coverage on main by 0.01%.

Modified Files with Diff Coverage (3)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: A
packages/agent/src/agent.ts100.0%
Coverage rating: A Coverage rating: A
packages/agent/src/routes/index.ts100.0%
New file Coverage rating: A
packages/agent/src/routes/ai/ai-proxy.ts100.0%
Total100.0%
🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@Scra3 Scra3 force-pushed the feat/ai-proxy-mistral-provider branch 8 times, most recently from c70778f to 25659a5 Compare December 16, 2025 05:54
alban bertolini and others added 2 commits December 16, 2025 07:08
- Add MistralConfiguration type with provider, model, and apiKey
- Add MistralUnprocessableError for Mistral-specific errors
- Implement Mistral dispatcher using @langchain/mistralai
- Return LangChain AIMessage format directly for frontend compatibility
- Add comprehensive tests for Mistral provider

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add MistralConfiguration type with provider, model, and apiKey
- Use @mistralai/mistralai SDK for Mistral calls
- Convert Mistral responses to OpenAI format for frontend compatibility
- Frontend always uses ChatOpenAI, backend handles provider abstraction
- Add comprehensive tests for both providers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@Scra3 Scra3 force-pushed the feat/ai-proxy-mistral-provider branch 3 times, most recently from 25e8a82 to f6d3514 Compare December 16, 2025 08:30
@Scra3 Scra3 changed the base branch from feat/add-ai-integration to main December 16, 2025 08:42
@Scra3 Scra3 changed the title feat(ai-proxy): add Mistral AI provider support feat(ai-proxy): feat(agent): add AI integration with addAI customization method Dec 16, 2025
@Scra3 Scra3 force-pushed the feat/ai-proxy-mistral-provider branch 3 times, most recently from 7136f39 to 7917528 Compare December 16, 2025 09:27
- Replace native Mistral SDK with @langchain/mistralai
- Add @langchain/openai for OpenAI provider
- Both providers return AIMessage, converted to OpenAI format
- Simplifies adding new providers in the future

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@Scra3 Scra3 force-pushed the feat/ai-proxy-mistral-provider branch from 7917528 to 7a5ff41 Compare December 16, 2025 09:33
alban bertolini and others added 3 commits December 16, 2025 11:33
- Fix incorrect provider in example (openai → mistral)
- Add error handling in handleAiProxy route (convert AI errors to UnprocessableError)
- Add validation for unsupported providers and missing API keys
- Narrow catch block scope and preserve error context with cause property
- Pin LangChain dependency versions for consistency
- Add Mistral model autocomplete with WithAutocomplete utility type
- Add tests for new validation errors and error handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Update JSDoc to explain that AI requests are forwarded to the agent
and processed locally, not accessible by Forest Admin for privacy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add detailed description of privacy benefits
- Document supported providers (openai, mistral)
- Add @param documentation for configuration properties
- Add @returns and @throws annotations
- Include examples for both OpenAI and Mistral providers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@Scra3
Copy link
Member Author

Scra3 commented Dec 16, 2025

Code review

Found 2 issues:

  1. Missing null check for args.query when accessing args.query['tool-name']. The query parameter is typed as optional (query?: Query), so if undefined, this will throw a TypeError.

return await remoteTools.invokeTool(
args.query['tool-name'],
(args.body as InvokeRemoteToolBody).inputs,
);
}

  1. Missing null check for args.body when accessing (args.body as InvokeRemoteToolBody).inputs. The body parameter is optional and can be undefined, which will throw a TypeError.

return await remoteTools.invokeTool(
args.query['tool-name'],
(args.body as InvokeRemoteToolBody).inputs,
);
}

Suggested fix for both issues:

if (args.route === 'invoke-remote-tool') {
  if (!args.query?.['tool-name']) {
    throw new AIUnprocessableError('Missing required query parameter: tool-name');
  }
  if (!args.body || !('inputs' in args.body)) {
    throw new AIUnprocessableError('Missing or invalid body for invoke-remote-tool');
  }
  return await remoteTools.invokeTool(
    args.query['tool-name'],
    (args.body as InvokeRemoteToolBody).inputs,
  );
}

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

alban bertolini and others added 12 commits December 16, 2025 12:41
- Replace custom LangChainClient type with BaseChatModel from @langchain/core
- Update KnownMistralModels with latest model names from Mistral docs
- Add magistral (reasoning), pixtral, and open-mistral-nemo models
- Fix AIError test to verify UnprocessableError type conversion
- Add validation tests for whitespace-only and undefined apiKey

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Mistral API uses "any" instead of "required" to force tool use.
Convert OpenAI's tool_choice: "required" to "any" for Mistral.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
MCP tools use Zod schemas internally. Convert them to JSON Schema
using toJsonSchema() before passing to the LLM, matching what
toolDefinitionsForFrontend does.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Pass tools and tool_choice directly to invoke() instead of using
bindTools(). This ensures tool_choice is properly passed to the
LLM API, fixing an issue where Mistral would return empty responses
despite tool_choice: "any".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Reverted to using bindTools() since invoke() options don't support
tools parameter. Added debug logging for Mistral to trace tool calls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Mistral requires tools to have a non-empty description. When MCP
servers provide tools without descriptions, we now add a fallback
description.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add logging before/after API call and in catch block to understand
where the request is failing with Mistral.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Remove $schema field from parameters (Mistral doesn't support it)
- Ensure all tools have non-empty descriptions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add timeout to detect if Mistral API is hanging.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Convert tool_choice "required" to "any" for Mistral
- Ensure all tools have non-empty descriptions
- Remove $schema field from tool parameters
- Clean up debug logging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Remove unnecessary Mistral-specific cleanup (description fallback,
$schema removal) - tested and works without it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@Scra3
Copy link
Member Author

Scra3 commented Dec 16, 2025

Auto code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants