Skip to content

Conversation

@Scra3
Copy link
Member

@Scra3 Scra3 commented Dec 8, 2025

Definition of Done

General

  • Write an explicit title for the Pull Request, following Conventional Commits specification
  • Test manually the implemented changes
  • Validate the code quality (indentation, syntax, style, simplicity, readability)

Security

  • Consider the security impact of the changes made

@qltysh
Copy link

qltysh bot commented Dec 8, 2025

2 new issues

Tool Category Rule Count
qlty Structure Function with many parameters (count = 4): makeRoutes 2

@Scra3
Copy link
Member Author

Scra3 commented Dec 8, 2025

Code review

Found 1 issue:

  1. Hardcoded Zendesk API token exposed in source code (security issue)

    The file contains what appears to be a real Zendesk API token hardcoded on line 10, paired with a specific subdomain forestadmin-91613. This token will be committed to the repository and exposed in git history. Even if intended as example code, real-looking credentials should be replaced with environment variables (e.g., process.env.ZENDESK_TOKEN) or obvious placeholder values like YOUR_TOKEN_HERE.

const client = zendesk.createClient({
username: 'email',
token: 'tFGjxI3V97pqlLOR4dGlMmoclIaV3CI2E49Ol5CN',
subdomain: 'forestadmin-91613',
});

🤖 Generated with Claude Code

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

import type { Clients, DispatchBody } from './provider-dispatcher';
import type { Messages, RemoteToolsApiKeys } from './remote-tools';

import { AIUnprocessableError, ProviderDispatcher } from './index';

Choose a reason for hiding this comment

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

🟡 MEDIUM - Circular dependency - router imports from index

Category: quality

Description:
router.ts imports from './index', and index.ts exports from './router', creating a circular dependency

Suggestion:
Import directly from './errors' and './provider-dispatcher' instead of from './index' to break the circular dependency

Confidence: 100%
Rule: arch_circular_dependency


if (args.route === 'ai-query') {
return await new ProviderDispatcher(this.aiClients, remoteTools).dispatch(
args.query.provider,

Choose a reason for hiding this comment

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

🟠 HIGH - Potential null/undefined access on args.query

Category: bug

Description:
Accessing args.query.provider without checking if args.query is defined. Query parameter is optional (query?: Query) and will cause TypeError if undefined.

Suggestion:
Add optional chaining: args.query?.provider or add null check before accessing

Confidence: 95%
Rule: bug_null_pointer


if (args.route === 'invoke-remote-tool') {
return await remoteTools.invokeTool(
args.query['tool-name'],

Choose a reason for hiding this comment

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

🟠 HIGH - Potential null/undefined access on args.query

Category: bug

Description:
Accessing args.query['tool-name'] without checking if args.query is defined. Query parameter is optional and will cause TypeError if undefined.

Suggestion:
Add optional chaining: args.query?.['tool-name'] or add null check before accessing

Confidence: 95%
Rule: bug_null_pointer

Comment on lines +16 to +17
this.sourceId = options.sourceId;
this.sourceType = options.sourceType;

Choose a reason for hiding this comment

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

🟠 HIGH - Assigning optional parameters to non-optional properties

Category: bug

Description:
Constructor accepts optional sourceId and sourceType but assigns them to non-optional class properties without validation. This will result in undefined values being stored.

Suggestion:
Either make properties optional (sourceId?: string) or provide default values in constructor: this.sourceId = options.sourceId ?? 'unknown'

Confidence: 90%
Rule: bug_missing_null_check


await mcpClient.loadTools();

expect(mcpClient.tools.length).toEqual(0);

Choose a reason for hiding this comment

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

🔵 LOW - Using toEqual for primitives instead of toBe

Category: quality

Description:
toEqual does deep comparison; use toBe for primitives

Suggestion:
Change expect(mcpClient.tools.length).toEqual(0) to expect(mcpClient.tools.length).toBe(0)

Confidence: 60%
Rule: test_js_expect_toequal_primitives


await mcpClient.loadTools();

expect(mcpClient.tools.length).toEqual(2);

Choose a reason for hiding this comment

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

🔵 LOW - Using toEqual for primitives instead of toBe

Category: quality

Description:
toEqual does deep comparison; use toBe for primitives

Suggestion:
Change expect(mcpClient.tools.length).toEqual(2) to expect(mcpClient.tools.length).toBe(2)

Confidence: 60%
Rule: test_js_expect_toequal_primitives

Comment on lines +56 to +59
`Failed to load tools from ${errors.length}/${Object.keys(this.mcpClients).length} ` +
`MCP server(s): ${errorMessage}`,

Choose a reason for hiding this comment

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

🔵 LOW - String concatenation instead of template literal

Category: quality

Description:
Using + operator for string concatenation instead of template literals reduces readability

Suggestion:
Replace string concatenation with template literal: Failed to load tools from ${errors.length}/${Object.keys(this.mcpClients).length} MCP server(s): ${errorMessage}

Confidence: 85%
Rule: ts_use_template_literals_instead_of_string_

Comment on lines +100 to +105
`Failed to close ${failures.length}/${results.length} MCP connections. ` +
`This may result in resource leaks.`,

Choose a reason for hiding this comment

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

🔵 LOW - String concatenation instead of template literal

Category: quality

Description:
Using + operator for string concatenation instead of template literals reduces readability

Suggestion:
Replace string concatenation with template literal: Failed to close ${failures.length}/${results.length} MCP connections. This may result in resource leaks.

Confidence: 85%
Rule: ts_use_template_literals_instead_of_string_

Comment on lines 75 to 76
// TODO: remove this route because it is no longer needed
// Do this after the front is removed the refresh button

Choose a reason for hiding this comment

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

🔵 LOW - TODO comment without ticket reference

Category: quality

Description:
TODO comment lacks ticket reference for tracking

Suggestion:
Add a ticket reference like TODO(#123) or TODO(JIRA-456) to track this work item

Confidence: 65%
Rule: general_todo_without_ticket

@diffray-bot
Copy link

diffray DiffRay AI Code Review

Free public review - Want AI code reviews on your PRs? Check out diffray.ai

Summary

Validated 47 issues: 32 kept (1 critical security, 3 high bugs, 28 medium/low quality), 15 filtered (low value or incorrect)

Issues Found: 33

See 33 individual line comment(s) for details.

Full issue list (click to expand)

🔴 CRITICAL - Hardcoded Zendesk API token exposed

File: packages/ai-proxy/src/examples/run-mcp-zendesk-server.ts:10

Category: security

Description: API token hardcoded in source code. If committed, token is publicly visible and can be used by attackers to access Zendesk account.

Suggestion: Remove the hardcoded token. Use environment variables: token: process.env.ZENDESK_API_TOKEN. Add .env to .gitignore and document required env vars in README.

Confidence: 100%

Rule: sec_secrets_scan


🟡 MEDIUM - Circular dependency - router imports from index

File: packages/ai-proxy/src/router.ts:5

Category: quality

Description: router.ts imports from './index', and index.ts exports from './router', creating a circular dependency

Suggestion: Import directly from './errors' and './provider-dispatcher' instead of from './index' to break the circular dependency

Confidence: 100%

Rule: arch_circular_dependency


🟠 HIGH - Potential null/undefined access on args.query

File: packages/ai-proxy/src/router.ts:58

Category: bug

Description: Accessing args.query.provider without checking if args.query is defined. Query parameter is optional (query?: Query) and will cause TypeError if undefined.

Suggestion: Add optional chaining: args.query?.provider or add null check before accessing

Confidence: 95%

Rule: bug_null_pointer


🟠 HIGH - Potential null/undefined access on args.query

File: packages/ai-proxy/src/router.ts:65

Category: bug

Description: Accessing args.query['tool-name'] without checking if args.query is defined. Query parameter is optional and will cause TypeError if undefined.

Suggestion: Add optional chaining: args.query?.['tool-name'] or add null check before accessing

Confidence: 95%

Rule: bug_null_pointer


🟠 HIGH - Assigning optional parameters to non-optional properties

File: packages/ai-proxy/src/remote-tool.ts:16-17

Category: bug

Description: Constructor accepts optional sourceId and sourceType but assigns them to non-optional class properties without validation. This will result in undefined values being stored.

Suggestion: Either make properties optional (sourceId?: string) or provide default values in constructor: this.sourceId = options.sourceId ?? 'unknown'

Confidence: 90%

Rule: bug_missing_null_check


🟡 MEDIUM - Duplicate Logger type definition

File: packages/ai-proxy/src/logger.ts:1-3

Category: quality

Description: New Logger type duplicates existing Logger types in forestadmin-client/src/types.ts and datasource-toolkit/src/factory.ts with different signature

Suggestion: Consider reusing existing Logger type from @forestadmin/forestadmin-client or @forestadmin/datasource-toolkit, or create a shared Logger interface in a common package to avoid multiple Logger type definitions across the codebase

Confidence: 85%

Rule: cons_duplicate_type_definition


🟡 MEDIUM - Missing JSDoc for exported Logger type

File: packages/ai-proxy/src/logger.ts:1-3

Category: quality

Description: Exported Logger interface lacks JSDoc documentation with description and param documentation

Suggestion: Add JSDoc comment explaining the Logger interface: /**

  • Logger interface for error logging throughout the AI proxy
  • @Property error - Logs error messages with optional arguments
    */

Confidence: 70%

Rule: ts_jsdoc_required_for_exported_apis


🟡 MEDIUM - Missing JSDoc for exported RemoteTool class

File: packages/ai-proxy/src/remote-tool.ts:5-18

Category: quality

Description: Exported RemoteTool class and its public members lack JSDoc documentation

Suggestion: Add JSDoc comments for the class, constructor, and public getter: /**

  • Represents a remote tool that can be invoked via MCP or direct server connection
    */

Confidence: 70%

Rule: ts_jsdoc_required_for_exported_apis


🟡 MEDIUM - Missing JSDoc for exported error classes

File: packages/ai-proxy/src/errors.ts:14-75

Category: quality

Description: All exported error classes lack JSDoc documentation explaining their purpose and when to use them

Suggestion: Add JSDoc to each error class explaining when it should be thrown, e.g. /** * Base error class for all AI-related errors * @param message - Error message describing what went wrong */

Confidence: 65%

Rule: ts_jsdoc_required_for_exported_apis


🟡 MEDIUM - Missing JSDoc for exported McpClient class

File: packages/ai-proxy/src/mcp-client.ts:11-27

Category: quality

Description: Exported McpClient class and its public methods lack JSDoc documentation

Suggestion: Add JSDoc for class and public methods loadTools(), testConnections(), and closeConnections() explaining their purpose, parameters, return values, and any thrown errors

Confidence: 70%

Rule: ts_jsdoc_required_for_exported_apis


🟡 MEDIUM - Missing JSDoc for exported RemoteTools class

File: packages/ai-proxy/src/remote-tools.ts:16-33

Category: quality

Description: Exported RemoteTools class constructor and public methods lack JSDoc documentation

Suggestion: Add JSDoc for constructor explaining apiKeys and tools parameters, and for invokeTool method explaining when AIToolNotFoundError and AIToolUnprocessableError are thrown

Confidence: 70%

Rule: ts_jsdoc_required_for_exported_apis


🟡 MEDIUM - Missing JSDoc for exported ProviderDispatcher class

File: packages/ai-proxy/src/provider-dispatcher.ts:26-43

Category: quality

Description: Exported ProviderDispatcher class and dispatch method lack JSDoc documentation

Suggestion: Add JSDoc explaining the class purpose and dispatch method parameters/return value, including @throws documentation for errors

Confidence: 70%

Rule: ts_jsdoc_required_for_exported_apis


🟡 MEDIUM - Missing JSDoc for exported Router class

File: packages/ai-proxy/src/router.ts:19-28

Category: quality

Description: Exported Router class constructor lacks JSDoc documentation for parameters

Suggestion: Add JSDoc explaining constructor params and route method: /**

  • Router for AI proxy requests
  • @param params - Configuration object
  • @param params.aiClients - AI client configurations (openai, etc)
  • @param params.localToolsApiKeys - API keys for local tools
  • @param params.logger - Optional logger for error reporting
    */

Confidence: 65%

Rule: ts_jsdoc_required_for_exported_apis


🟡 MEDIUM - Missing JSDoc for exported function

File: packages/ai-proxy/src/index.ts:13-15

Category: quality

Description: Exported function validMcpConfigurationOrThrow lacks JSDoc documentation

Suggestion: Add JSDoc: /**

  • Validates MCP configuration and throws if invalid
  • @param mcpConfig - MCP configuration to validate
  • @throws {McpConfigError} When configuration is invalid
  • @returns Validated configuration
    */

Confidence: 70%

Rule: ts_jsdoc_required_for_exported_apis


🟡 MEDIUM - Default export used instead of named export

File: packages/ai-proxy/src/mcp-client.ts:11

Category: quality

Description: Default exports reduce clarity and make refactoring harder

Suggestion: Use named export: export class McpClient instead of export default class McpClient

Confidence: 65%

Rule: ts_avoid_default_exports


🟡 MEDIUM - Default export used instead of named export

File: packages/ai-proxy/src/remote-tool.ts:5

Category: quality

Description: Default exports reduce clarity and make refactoring harder

Suggestion: Use named export: export class RemoteTool instead of export default class RemoteTool

Confidence: 65%

Rule: ts_avoid_default_exports


🟡 MEDIUM - Default export used instead of named export

File: packages/ai-proxy/src/mcp-config-checker.ts:5

Category: quality

Description: Default exports reduce clarity and make refactoring harder

Suggestion: Use named export: export class McpConfigChecker instead of export default class McpConfigChecker

Confidence: 65%

Rule: ts_avoid_default_exports


🟠 HIGH - Tight coupling - Direct instantiation of dependencies

File: packages/ai-proxy/src/router.ts:51-57

Category: quality

Description: Router.route() directly instantiates McpClient, RemoteTools, and ProviderDispatcher, making testing and mocking difficult

Suggestion: Pass dependencies via constructor or factory pattern. Consider injecting McpClientFactory, RemoteToolsFactory instead of creating instances directly

Confidence: 70%

Rule: arch_tight_coupling


🟠 HIGH - Single Responsibility Principle violation

File: packages/ai-proxy/src/router.ts:46-97

Category: quality

Description: Router.route() handles multiple responsibilities: routing logic, MCP client lifecycle management, remote tools creation, provider dispatching, and cleanup/error handling

Suggestion: Split responsibilities: extract MCP client lifecycle to McpClientManager, extract route handling logic to separate handler classes per route type

Confidence: 75%

Rule: arch_srp_violation


🔵 LOW - Properties not marked as readonly

File: packages/ai-proxy/src/remote-tool.ts:6-8

Category: quality

Description: Properties base, sourceId, and sourceType are never reassigned after construction but not marked readonly

Suggestion: Mark properties as readonly: readonly base, readonly sourceId, readonly sourceType

Confidence: 85%

Rule: ts_mark_properties_as_readonly_if_not_reassigned


🔵 LOW - Missing JSDoc for exported function

File: packages/ai-proxy/src/examples/simple-mcp-server.ts:10-93

Category: quality

Description: Default exported function lacks JSDoc with parameter and return value documentation

Suggestion: Add JSDoc: /**

  • Creates an Express server for handling MCP requests over HTTP
  • @param server - The MCP server instance
  • @param port - Port number to listen on
  • @param secureToken - Bearer token for authentication
  • @returns Express server instance
    */

Confidence: 65%

Rule: ts_jsdoc_required_for_exported_apis


🔵 LOW - TODO comment indicates dead code

File: packages/ai-proxy/src/router.ts:74-77

Category: quality

Description: Route 'refresh-remote-tools' has TODO comment indicating it should be removed

Suggestion: Remove this route once the frontend removes the refresh button, or track this in a proper issue tracker instead of code comments

Confidence: 70%

Rule: quality_commented_code


🔵 LOW - Duplicated error response logic

File: packages/ai-proxy/src/examples/simple-mcp-server.ts:68-87

Category: quality

Description: GET and DELETE handlers have identical error response logic

Suggestion: Extract to a helper function: sendMethodNotAllowed(res) to avoid duplication

Confidence: 75%

Rule: ts_extract_duplicated_logic_into_functions


🔵 LOW - Using toEqual for primitives instead of toBe

File: packages/ai-proxy/test/remote-tools.test.ts:15

Category: quality

Description: toEqual does deep comparison; use toBe for primitives

Suggestion: Change expect(remoteTools.tools.length).toEqual(0) to expect(remoteTools.tools.length).toBe(0)

Confidence: 60%

Rule: test_js_expect_toequal_primitives


🔵 LOW - Using toEqual for primitives instead of toBe

File: packages/ai-proxy/test/remote-tools.test.ts:28

Category: quality

Description: toEqual does deep comparison; use toBe for primitives

Suggestion: Change expect(remoteTools.tools.length).toEqual(1) to expect(remoteTools.tools.length).toBe(1)

Confidence: 60%

Rule: test_js_expect_toequal_primitives


🔵 LOW - Using toEqual for primitives instead of toBe

File: packages/ai-proxy/test/remote-tools.test.ts:44

Category: quality

Description: toEqual does deep comparison; use toBe for primitives

Suggestion: Change expect(remoteTools.tools.length).toEqual(2) to expect(remoteTools.tools.length).toBe(2)

Confidence: 60%

Rule: test_js_expect_toequal_primitives


🔵 LOW - Using toEqual for primitives instead of toBe

File: packages/ai-proxy/test/remote-tools.test.ts:45

Category: quality

Description: toEqual does deep comparison; use toBe for primitives

Suggestion: Change expect(remoteTools.tools[0].base.name).toEqual('tool1') to expect(remoteTools.tools[0].base.name).toBe('tool1')

Confidence: 60%

Rule: test_js_expect_toequal_primitives


🔵 LOW - Using toEqual for primitives instead of toBe

File: packages/ai-proxy/test/remote-tools.test.ts:73

Category: quality

Description: toEqual does deep comparison; use toBe for primitives

Suggestion: Change expect(response).toEqual('response') to expect(response).toBe('response')

Confidence: 60%

Rule: test_js_expect_toequal_primitives


🔵 LOW - Using toEqual for primitives instead of toBe

File: packages/ai-proxy/test/mcp-client.test.ts:80

Category: quality

Description: toEqual does deep comparison; use toBe for primitives

Suggestion: Change expect(mcpClient.tools.length).toEqual(0) to expect(mcpClient.tools.length).toBe(0)

Confidence: 60%

Rule: test_js_expect_toequal_primitives


🔵 LOW - Using toEqual for primitives instead of toBe

File: packages/ai-proxy/test/mcp-client.test.ts:108

Category: quality

Description: toEqual does deep comparison; use toBe for primitives

Suggestion: Change expect(mcpClient.tools.length).toEqual(2) to expect(mcpClient.tools.length).toBe(2)

Confidence: 60%

Rule: test_js_expect_toequal_primitives


🔵 LOW - String concatenation instead of template literal

File: packages/ai-proxy/src/mcp-client.ts:56-57

Category: quality

Description: Using + operator for string concatenation instead of template literals reduces readability

Suggestion: Replace string concatenation with template literal: Failed to load tools from ${errors.length}/${Object.keys(this.mcpClients).length} MCP server(s): ${errorMessage}

Confidence: 85%

Rule: ts_use_template_literals_instead_of_string_


🔵 LOW - String concatenation instead of template literal

File: packages/ai-proxy/src/mcp-client.ts:100-101

Category: quality

Description: Using + operator for string concatenation instead of template literals reduces readability

Suggestion: Replace string concatenation with template literal: Failed to close ${failures.length}/${results.length} MCP connections. This may result in resource leaks.

Confidence: 85%

Rule: ts_use_template_literals_instead_of_string_


🔵 LOW - TODO comment without ticket reference

File: packages/ai-proxy/src/router.ts:75-76

Category: quality

Description: TODO comment lacks ticket reference for tracking

Suggestion: Add a ticket reference like TODO(#123) or TODO(JIRA-456) to track this work item

Confidence: 65%

Rule: general_todo_without_ticket



Powered by DiffRay - AI Code Review | Learn more

@qltysh
Copy link

qltysh bot commented Dec 11, 2025

Coverage Impact

This PR will not change total coverage.

Modified Files with Diff Coverage (7)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: A
packages/forestadmin-client/src/forest-admin-client-with-cache.ts100.0%
Coverage rating: A Coverage rating: A
packages/agent/src/agent.ts100.0%
Coverage rating: A Coverage rating: A
packages/agent/src/routes/index.ts66.7%175
Coverage rating: A Coverage rating: A
packages/forestadmin-client/src/build-application-services.ts100.0%
Coverage rating: A Coverage rating: A
packages/forestadmin-client/src/permissions/forest-http-api.ts100.0%
New file Coverage rating: A
packages/agent/src/routes/ai/ai-proxy.ts100.0%
New file Coverage rating: A
packages/forestadmin-client/src/mcp-server-config/index.ts100.0%
Total96.4%
🤖 Increase coverage with AI coding...
In the `feature/customize-ai-llm` branch, add test coverage for this new code:

- `packages/agent/src/routes/index.ts` -- Line 175

🚦 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 feature/customize-ai-llm branch 2 times, most recently from f6e938e to 902146f Compare December 11, 2025 07:43
@Scra3 Scra3 changed the base branch from main to chore/upgrade-typescript-5 December 11, 2025 08:24
Base automatically changed from chore/upgrade-typescript-5 to main December 11, 2025 09:32
alban bertolini and others added 21 commits December 11, 2025 10:43
Add a new `customizeAiLlm` method to the Agent class that enables AI-powered
features through the `/forest/ai-proxy/*` endpoints. This includes:

- New `@forestadmin/ai-proxy` package with OpenAI integration and MCP support
- `AiLlmConfiguration` type derived from `Clients` type
- `AiProvider` type exported for type-safe provider names
- Schema metadata update with `aiLlm` field to advertise AI capabilities
- New `AiProxyRoute` for handling AI proxy requests with JWT authentication

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…Admin server

Add a new service to fetch MCP server configurations from the Forest Admin
server endpoint `/api/mcp-server-configs-with-details`. The configurations
are then converted and passed to the AI proxy router for each request.

- Add `McpServerConfig` type and `getMcpServerConfigs` to `ForestAdminServerInterface`
- Create `McpServerConfigService` to fetch configurations
- Expose `mcpServerConfigService` in `ForestAdminClient`
- Update `AiProxyRoute` to fetch and convert MCP configs per request

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…tom logger

Replace the custom Logger type with the Logger from @forestadmin/datasource-toolkit
which has the standard signature (level, message, error?). This ensures consistency
across all Forest Admin packages.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add customizeAiLlm example usage in agent.ts
- Fix import ordering (alphabetical/style)
- Update @forestadmin/agent version in example package

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Zod v4 types are incompatible with TypeScript 4.9. Force resolution
to zod 3.23.8 to avoid build errors from langchain dependencies
pulling in newer zod versions.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Upgrade TypeScript from 4.9.4 to 5.6.3
- Upgrade @langchain/core to 1.1.4
- Upgrade @langchain/mcp-adapters to 1.0.3
- Add @langchain/langgraph 1.0.4 as required peer dependency
- Remove zod version constraint to allow latest versions

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Match the snake_case format used by liana_features and liana_version.
Also fix TypeScript 5 strict type error in update-relation.ts.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The refresh-remote-tools route is no longer needed as MCP tools
are loaded fresh on each request.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Simplified API from:
```
.customizeAiLlm({
  aiClients: {
    openai: {
      clientOptions: { apiKey: '...' },
      chatConfiguration: { model: 'gpt-4' }
    }
  }
})
```

To:
```
.customizeAiLlm({
  openai: {
    apiKey: '...',
    model: 'gpt-4'
  }
})
```

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Rename customizeAiLlm() to customizeAi()
- Rename AiLlmConfiguration to AiConfiguration
- Rename aiLlmConfig to aiConfig

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Use OpenAI's ClientOptions type directly instead of a custom type.
This gives users access to all OpenAI SDK options (baseURL, timeout,
organization, etc.) without us having to maintain our own type.

```typescript
.customizeAi({
  openai: {
    apiKey: process.env.OPENAI_API_KEY,
    model: 'gpt-4',
    // All OpenAI ClientOptions available
    baseURL: 'https://custom.endpoint.com',
    timeout: 30000
  }
})
```

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Allow configuring multiple AI clients with a name identifier.
Each configuration includes provider, name, and provider-specific options.

```typescript
agent.customizeAi([
  {
    name: 'gpt4-default',
    provider: 'openai',
    apiKey: process.env.OPENAI_API_KEY,
    model: 'gpt-4'
  },
  {
    name: 'gpt4-fast',
    provider: 'openai',
    apiKey: process.env.OPENAI_API_KEY,
    model: 'gpt-4-turbo',
    timeout: 5000
  }
]);
```

API route now uses client-name query parameter:
- /ai-query?client-name=gpt4-default

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Remove 'name' field from AiConfiguration (single AI supported for now)
- Change customizeAi() to accept single configuration instead of array
- Type 'model' field from ChatCompletionCreateParamsNonStreaming
- Add AINotConfiguredError for better error handling

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Rename customizeAi() to addAi() for consistency with addDataSource/addChart
- Add tests for addAi() method (single call restriction, schema meta)
- Update AINotConfiguredError message
- Remove fake Mistral configuration
- Add mcpServerConfigService to test factory

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Prepare for future multi-LLM support by using an array of objects in schema meta.
- Rename ai_llm to ai_llms (Array<{ provider: string }> | null)
- When AI is configured, returns [{ provider: 'openai' }]

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Changed langchain versions:
- @langchain/core: 1.1.4 -> 0.3.79
- @langchain/langgraph: 1.0.4 -> 0.4.9
- @langchain/community: 0.3.57 -> 0.3.58
- @langchain/mcp-adapters: 1.0.3 -> 0.6.0

These versions use zod@^3.25.32 instead of [email protected] which requires TypeScript 5.
Since TypeScript 5 is already in use due to zod 3.25+ shipping with v4/ folder.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Reverted langchain packages to latest versions:
- @langchain/core: 1.1.4
- @langchain/langgraph: 1.0.4
- @langchain/community: 0.3.57
- @langchain/mcp-adapters: 1.0.3

TypeScript 5 upgrade is required due to zod 4.x dependency.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Replace fishery Factory with simple build() function for ForestAdminServerInterface
- Add mcpServerConfig factory
- Add ai_llms field to schema test data
- Update schema hash expectations
- Add getMcpServerConfigs to server interface mock

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
alban bertolini and others added 3 commits December 11, 2025 10:43
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Move the AI proxy endpoint from /forest/ai-proxy/* to /forest/_internal/ai-proxy/*
to avoid potential conflicts with user-defined routes.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@Scra3 Scra3 force-pushed the feature/customize-ai-llm branch from b894b11 to 541085a Compare December 11, 2025 09:44
alban bertolini and others added 5 commits December 11, 2025 11:15
- Add tests for AiProxyRoute (constructor, type, setupRoutes, handleAiProxy)
- Add tests for McpServerConfigFromApiService.getConfiguration
- Add test for ForestHttpApi.getMcpServerConfigs

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add eslint-disable comments for @modelcontextprotocol/sdk imports that
require .js extensions, and fix import order in test files.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ig test

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Cover the case when aiConfiguration is provided to makeRoutes.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
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.

3 participants