@forestadmin/ai-proxy 1.3.1 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/errors.d.ts +4 -1
- package/dist/errors.js +11 -4
- package/dist/index.js +1 -1
- package/dist/provider-dispatcher.d.ts +4 -32
- package/dist/provider-dispatcher.js +2 -29
- package/dist/provider.d.ts +26 -0
- package/dist/provider.js +3 -0
- package/dist/router.d.ts +9 -16
- package/dist/router.js +62 -34
- package/dist/schemas/route.d.ts +81 -0
- package/dist/schemas/route.js +64 -0
- package/dist/supported-models.d.ts +7 -0
- package/dist/supported-models.js +81 -0
- package/package.json +2 -2
package/dist/errors.d.ts
CHANGED
|
@@ -16,6 +16,9 @@ export declare class AIError extends Error {
|
|
|
16
16
|
export declare class AIBadRequestError extends AIError {
|
|
17
17
|
constructor(message: string);
|
|
18
18
|
}
|
|
19
|
+
export declare class AIModelNotSupportedError extends AIBadRequestError {
|
|
20
|
+
constructor(model: string);
|
|
21
|
+
}
|
|
19
22
|
export declare class AINotFoundError extends AIError {
|
|
20
23
|
constructor(message: string);
|
|
21
24
|
}
|
|
@@ -23,7 +26,7 @@ export declare class AIUnprocessableError extends AIError {
|
|
|
23
26
|
constructor(message: string);
|
|
24
27
|
}
|
|
25
28
|
export declare class AINotConfiguredError extends AIError {
|
|
26
|
-
constructor();
|
|
29
|
+
constructor(message?: string);
|
|
27
30
|
}
|
|
28
31
|
export declare class OpenAIUnprocessableError extends AIUnprocessableError {
|
|
29
32
|
constructor(message: string);
|
package/dist/errors.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* -------------------------------------
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.McpConfigError = exports.McpConflictError = exports.McpConnectionError = exports.McpError = exports.AIToolNotFoundError = exports.AIToolUnprocessableError = exports.OpenAIUnprocessableError = exports.AINotConfiguredError = exports.AIUnprocessableError = exports.AINotFoundError = exports.AIBadRequestError = exports.AIError = void 0;
|
|
14
|
+
exports.McpConfigError = exports.McpConflictError = exports.McpConnectionError = exports.McpError = exports.AIToolNotFoundError = exports.AIToolUnprocessableError = exports.OpenAIUnprocessableError = exports.AINotConfiguredError = exports.AIUnprocessableError = exports.AINotFoundError = exports.AIModelNotSupportedError = exports.AIBadRequestError = exports.AIError = void 0;
|
|
15
15
|
// eslint-disable-next-line max-classes-per-file
|
|
16
16
|
class AIError extends Error {
|
|
17
17
|
constructor(message, status = 422) {
|
|
@@ -31,6 +31,13 @@ class AIBadRequestError extends AIError {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
exports.AIBadRequestError = AIBadRequestError;
|
|
34
|
+
class AIModelNotSupportedError extends AIBadRequestError {
|
|
35
|
+
constructor(model) {
|
|
36
|
+
super(`Model '${model}' does not support tools. Please use a model that supports function calling.`);
|
|
37
|
+
this.name = 'AIModelNotSupportedError';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.AIModelNotSupportedError = AIModelNotSupportedError;
|
|
34
41
|
class AINotFoundError extends AIError {
|
|
35
42
|
constructor(message) {
|
|
36
43
|
super(message, 404);
|
|
@@ -46,8 +53,8 @@ class AIUnprocessableError extends AIError {
|
|
|
46
53
|
}
|
|
47
54
|
exports.AIUnprocessableError = AIUnprocessableError;
|
|
48
55
|
class AINotConfiguredError extends AIError {
|
|
49
|
-
constructor() {
|
|
50
|
-
super(
|
|
56
|
+
constructor(message = 'AI is not configured') {
|
|
57
|
+
super(message, 422);
|
|
51
58
|
this.name = 'AINotConfiguredError';
|
|
52
59
|
}
|
|
53
60
|
}
|
|
@@ -101,4 +108,4 @@ class McpConfigError extends McpError {
|
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
exports.McpConfigError = McpConfigError;
|
|
104
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
111
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7R0FVRzs7O0FBRUgsZ0RBQWdEO0FBQ2hELE1BQWEsT0FBUSxTQUFRLEtBQUs7SUFHaEMsWUFBWSxPQUFlLEVBQUUsTUFBTSxHQUFHLEdBQUc7UUFDdkMsSUFBSSxNQUFNLEdBQUcsR0FBRyxJQUFJLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQztZQUNqQyxNQUFNLElBQUksVUFBVSxDQUFDLDZCQUE2QixNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQzlELENBQUM7UUFFRCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLFNBQVMsQ0FBQztRQUN0QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN2QixDQUFDO0NBQ0Y7QUFaRCwwQkFZQztBQUVELE1BQWEsaUJBQWtCLFNBQVEsT0FBTztJQUM1QyxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNwQixJQUFJLENBQUMsSUFBSSxHQUFHLG1CQUFtQixDQUFDO0lBQ2xDLENBQUM7Q0FDRjtBQUxELDhDQUtDO0FBRUQsTUFBYSx3QkFBeUIsU0FBUSxpQkFBaUI7SUFDN0QsWUFBWSxLQUFhO1FBQ3ZCLEtBQUssQ0FDSCxVQUFVLEtBQUssOEVBQThFLENBQzlGLENBQUM7UUFDRixJQUFJLENBQUMsSUFBSSxHQUFHLDBCQUEwQixDQUFDO0lBQ3pDLENBQUM7Q0FDRjtBQVBELDREQU9DO0FBRUQsTUFBYSxlQUFnQixTQUFRLE9BQU87SUFDMUMsWUFBWSxPQUFlO1FBQ3pCLEtBQUssQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDcEIsSUFBSSxDQUFDLElBQUksR0FBRyxpQkFBaUIsQ0FBQztJQUNoQyxDQUFDO0NBQ0Y7QUFMRCwwQ0FLQztBQUVELE1BQWEsb0JBQXFCLFNBQVEsT0FBTztJQUMvQyxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNwQixJQUFJLENBQUMsSUFBSSxHQUFHLHNCQUFzQixDQUFDO0lBQ3JDLENBQUM7Q0FDRjtBQUxELG9EQUtDO0FBRUQsTUFBYSxvQkFBcUIsU0FBUSxPQUFPO0lBQy9DLFlBQVksT0FBTyxHQUFHLHNCQUFzQjtRQUMxQyxLQUFLLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3BCLElBQUksQ0FBQyxJQUFJLEdBQUcsc0JBQXNCLENBQUM7SUFDckMsQ0FBQztDQUNGO0FBTEQsb0RBS0M7QUFFRCxNQUFhLHdCQUF5QixTQUFRLG9CQUFvQjtJQUNoRSxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxhQUFhLENBQUM7SUFDNUIsQ0FBQztDQUNGO0FBTEQsNERBS0M7QUFFRCxNQUFhLHdCQUF5QixTQUFRLG9CQUFvQjtJQUNoRSxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxhQUFhLENBQUM7SUFDNUIsQ0FBQztDQUNGO0FBTEQsNERBS0M7QUFFRCxNQUFhLG1CQUFvQixTQUFRLGVBQWU7SUFDdEQsWUFBWSxPQUFlO1FBQ3pCLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNmLElBQUksQ0FBQyxJQUFJLEdBQUcscUJBQXFCLENBQUM7SUFDcEMsQ0FBQztDQUNGO0FBTEQsa0RBS0M7QUFFRCxNQUFhLFFBQVMsU0FBUSxPQUFPO0lBQ25DLFlBQVksT0FBZTtRQUN6QixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQztJQUN6QixDQUFDO0NBQ0Y7QUFMRCw0QkFLQztBQUVELE1BQWEsa0JBQW1CLFNBQVEsUUFBUTtJQUM5QyxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxvQkFBb0IsQ0FBQztJQUNuQyxDQUFDO0NBQ0Y7QUFMRCxnREFLQztBQUVELE1BQWEsZ0JBQWlCLFNBQVEsUUFBUTtJQUM1QyxZQUFZLFVBQWtCO1FBQzVCLEtBQUssQ0FBQyxJQUFJLFVBQVUsbUNBQW1DLENBQUMsQ0FBQztRQUN6RCxJQUFJLENBQUMsSUFBSSxHQUFHLGtCQUFrQixDQUFDO0lBQ2pDLENBQUM7Q0FDRjtBQUxELDRDQUtDO0FBRUQsTUFBYSxjQUFlLFNBQVEsUUFBUTtJQUMxQyxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxnQkFBZ0IsQ0FBQztJQUMvQixDQUFDO0NBQ0Y7QUFMRCx3Q0FLQyJ9
|
package/dist/index.js
CHANGED
|
@@ -28,4 +28,4 @@ __exportStar(require("./errors"), exports);
|
|
|
28
28
|
function validMcpConfigurationOrThrow(mcpConfig) {
|
|
29
29
|
return mcp_config_checker_1.default.check(mcpConfig);
|
|
30
30
|
}
|
|
31
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQVdBLG9FQUVDO0FBWEQsOEVBQW9EO0FBRXBELHdEQUFzQztBQUN0QyxpREFBK0I7QUFDL0IsMkNBQXlCO0FBQ3pCLCtDQUE2QjtBQUM3Qix5REFBdUM7QUFDdkMsMkNBQXlCO0FBRXpCLFNBQWdCLDRCQUE0QixDQUFDLFNBQTJCO0lBQ3RFLE9BQU8sNEJBQWdCLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQzNDLENBQUMifQ==
|
|
@@ -1,36 +1,8 @@
|
|
|
1
|
+
import type { AiConfiguration, ChatCompletionResponse } from './provider';
|
|
1
2
|
import type { RemoteTools } from './remote-tools';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
/**
|
|
6
|
-
* Base configuration common to all AI providers.
|
|
7
|
-
*/
|
|
8
|
-
export type BaseAiConfiguration = {
|
|
9
|
-
name: string;
|
|
10
|
-
provider: AiProvider;
|
|
11
|
-
model: string;
|
|
12
|
-
apiKey?: string;
|
|
13
|
-
};
|
|
14
|
-
/**
|
|
15
|
-
* OpenAI-specific configuration.
|
|
16
|
-
* Extends base with all ChatOpenAI options (temperature, maxTokens, configuration, etc.)
|
|
17
|
-
*/
|
|
18
|
-
export type OpenAiConfiguration = Omit<BaseAiConfiguration, 'model'> & Omit<ChatOpenAIFields, 'model' | 'apiKey'> & {
|
|
19
|
-
provider: 'openai';
|
|
20
|
-
model: OpenAIChatModelId | (string & NonNullable<unknown>);
|
|
21
|
-
};
|
|
22
|
-
export type AiProvider = 'openai';
|
|
23
|
-
export type AiConfiguration = OpenAiConfiguration;
|
|
24
|
-
export type ChatCompletionResponse = OpenAI.Chat.Completions.ChatCompletion;
|
|
25
|
-
export type ChatCompletionMessage = OpenAI.Chat.Completions.ChatCompletionMessageParam;
|
|
26
|
-
export type ChatCompletionTool = OpenAI.Chat.Completions.ChatCompletionTool;
|
|
27
|
-
export type ChatCompletionToolChoice = OpenAI.Chat.Completions.ChatCompletionToolChoiceOption;
|
|
28
|
-
export type DispatchBody = {
|
|
29
|
-
messages: ChatCompletionMessage[];
|
|
30
|
-
tools?: ChatCompletionTool[];
|
|
31
|
-
tool_choice?: ChatCompletionToolChoice;
|
|
32
|
-
parallel_tool_calls?: boolean;
|
|
33
|
-
};
|
|
3
|
+
import type { DispatchBody } from './schemas/route';
|
|
4
|
+
export type { AiConfiguration, AiProvider, BaseAiConfiguration, ChatCompletionMessage, ChatCompletionResponse, ChatCompletionTool, ChatCompletionToolChoice, OpenAiConfiguration, } from './provider';
|
|
5
|
+
export type { DispatchBody } from './schemas/route';
|
|
34
6
|
export declare class ProviderDispatcher {
|
|
35
7
|
private readonly chatModel;
|
|
36
8
|
private readonly remoteTools;
|
|
@@ -1,37 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ProviderDispatcher = void 0;
|
|
4
|
-
exports.isModelSupportingTools = isModelSupportingTools;
|
|
5
4
|
const function_calling_1 = require("@langchain/core/utils/function_calling");
|
|
6
5
|
const openai_1 = require("@langchain/openai");
|
|
7
6
|
const errors_1 = require("./errors");
|
|
8
|
-
/**
|
|
9
|
-
* OpenAI model prefixes that do NOT support function calling (tools).
|
|
10
|
-
* Unknown models are allowed.
|
|
11
|
-
* @see https://platform.openai.com/docs/guides/function-calling
|
|
12
|
-
*/
|
|
13
|
-
const OPENAI_MODELS_WITHOUT_TOOLS_SUPPORT = [
|
|
14
|
-
'gpt-4',
|
|
15
|
-
'gpt-3.5-turbo',
|
|
16
|
-
'gpt-3.5',
|
|
17
|
-
'text-davinci',
|
|
18
|
-
'davinci',
|
|
19
|
-
'curie',
|
|
20
|
-
'babbage',
|
|
21
|
-
'ada',
|
|
22
|
-
];
|
|
23
|
-
/**
|
|
24
|
-
* Exceptions to the unsupported list - these models DO support tools
|
|
25
|
-
* even though they start with an unsupported prefix.
|
|
26
|
-
*/
|
|
27
|
-
const OPENAI_MODELS_EXCEPTIONS = ['gpt-4-turbo', 'gpt-4o', 'gpt-4.1'];
|
|
28
|
-
function isModelSupportingTools(model) {
|
|
29
|
-
const isException = OPENAI_MODELS_EXCEPTIONS.some(exception => model === exception || model.startsWith(`${exception}-`));
|
|
30
|
-
if (isException)
|
|
31
|
-
return true;
|
|
32
|
-
const isKnownUnsupported = OPENAI_MODELS_WITHOUT_TOOLS_SUPPORT.some(unsupported => model === unsupported || model.startsWith(`${unsupported}-`));
|
|
33
|
-
return !isKnownUnsupported;
|
|
34
|
-
}
|
|
35
7
|
class ProviderDispatcher {
|
|
36
8
|
constructor(configuration, remoteTools) {
|
|
37
9
|
this.chatModel = null;
|
|
@@ -39,6 +11,7 @@ class ProviderDispatcher {
|
|
|
39
11
|
if (configuration?.provider === 'openai') {
|
|
40
12
|
const { provider, name, ...chatOpenAIOptions } = configuration;
|
|
41
13
|
this.chatModel = new openai_1.ChatOpenAI({
|
|
14
|
+
maxRetries: 0, // No retries by default - this lib is a passthrough
|
|
42
15
|
...chatOpenAIOptions,
|
|
43
16
|
__includeRawResponse: true,
|
|
44
17
|
});
|
|
@@ -93,4 +66,4 @@ class ProviderDispatcher {
|
|
|
93
66
|
}
|
|
94
67
|
}
|
|
95
68
|
exports.ProviderDispatcher = ProviderDispatcher;
|
|
96
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
69
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlkZXItZGlzcGF0Y2hlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9wcm92aWRlci1kaXNwYXRjaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUtBLDZFQUFpRjtBQUNqRiw4Q0FBK0M7QUFFL0MscUNBQTBFO0FBZTFFLE1BQWEsa0JBQWtCO0lBSzdCLFlBQVksYUFBcUMsRUFBRSxXQUF3QjtRQUoxRCxjQUFTLEdBQXNCLElBQUksQ0FBQztRQUtuRCxJQUFJLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztRQUUvQixJQUFJLGFBQWEsRUFBRSxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDekMsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsR0FBRyxpQkFBaUIsRUFBRSxHQUFHLGFBQWEsQ0FBQztZQUMvRCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksbUJBQVUsQ0FBQztnQkFDOUIsVUFBVSxFQUFFLENBQUMsRUFBRSxvREFBb0Q7Z0JBQ25FLEdBQUcsaUJBQWlCO2dCQUNwQixvQkFBb0IsRUFBRSxJQUFJO2FBQzNCLENBQUMsQ0FBQztRQUNMLENBQUM7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFrQjtRQUMvQixJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3BCLE1BQU0sSUFBSSw2QkFBb0IsRUFBRSxDQUFDO1FBQ25DLENBQUM7UUFFRCxNQUFNLEVBQ0osS0FBSyxFQUNMLFFBQVEsRUFDUixXQUFXLEVBQUUsVUFBVSxFQUN2QixtQkFBbUIsRUFBRSxpQkFBaUIsR0FDdkMsR0FBRyxJQUFJLENBQUM7UUFFVCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDeEQsTUFBTSxLQUFLLEdBQUcsYUFBYSxFQUFFLE1BQU07WUFDakMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLGFBQWEsRUFBRTtnQkFDdEMsV0FBVyxFQUFFLFVBQVU7Z0JBQ3ZCLG1CQUFtQixFQUFFLGlCQUFpQjthQUN2QyxDQUFDO1lBQ0osQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUM7UUFFbkIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsTUFBTSxDQUFDLFFBQTZCLENBQUMsQ0FBQztZQUVuRSxnREFBZ0Q7WUFDaEQsTUFBTSxXQUFXLEdBQUcsUUFBUSxDQUFDLGlCQUFpQixDQUFDLGNBQXdDLENBQUM7WUFFeEYsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO2dCQUNqQixNQUFNLElBQUksaUNBQXdCLENBQ2hDLDZFQUE2RSxDQUM5RSxDQUFDO1lBQ0osQ0FBQztZQUVELE9BQU8sV0FBVyxDQUFDO1FBQ3JCLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxLQUFLLFlBQVksaUNBQXdCO2dCQUFFLE1BQU0sS0FBSyxDQUFDO1lBRTNELE1BQU0sR0FBRyxHQUFHLEtBQW9DLENBQUM7WUFFakQsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO2dCQUN2QixNQUFNLElBQUksaUNBQXdCLENBQUMsd0JBQXdCLEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQzVFLENBQUM7WUFFRCxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU0sSUFBSSxpQ0FBd0IsQ0FBQywwQkFBMEIsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDOUUsQ0FBQztZQUVELE1BQU0sSUFBSSxpQ0FBd0IsQ0FBQywrQkFBK0IsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDbkYsQ0FBQztJQUNILENBQUM7SUFFTyxxQkFBcUIsQ0FBQyxLQUE0QjtRQUN4RCxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUVsRCxNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUNoRSxJQUFBLDBDQUF1QixFQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FDekMsQ0FBQztRQUVGLE9BQU8sS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUN0QixJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssVUFBVTtnQkFBRSxPQUFPLElBQUksQ0FBQztZQUUxQyxNQUFNLFlBQVksR0FBRyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDMUYsSUFBSSxZQUFZO2dCQUFFLE9BQU8sRUFBRSxHQUFHLElBQUksRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFFLENBQUM7WUFFN0QsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQXBGRCxnREFvRkMifQ==
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ChatOpenAIFields, OpenAIChatModelId } from '@langchain/openai';
|
|
2
|
+
import type OpenAI from 'openai';
|
|
3
|
+
export type ChatCompletionResponse = OpenAI.Chat.Completions.ChatCompletion;
|
|
4
|
+
export type ChatCompletionMessage = OpenAI.Chat.Completions.ChatCompletionMessageParam;
|
|
5
|
+
export type ChatCompletionTool = OpenAI.Chat.Completions.ChatCompletionTool;
|
|
6
|
+
export type ChatCompletionToolChoice = OpenAI.Chat.Completions.ChatCompletionToolChoiceOption;
|
|
7
|
+
export type AiProvider = 'openai';
|
|
8
|
+
/**
|
|
9
|
+
* Base configuration common to all AI providers.
|
|
10
|
+
*/
|
|
11
|
+
export type BaseAiConfiguration = {
|
|
12
|
+
name: string;
|
|
13
|
+
provider: AiProvider;
|
|
14
|
+
model: string;
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* OpenAI-specific configuration.
|
|
19
|
+
* Extends base with all ChatOpenAI options (temperature, maxTokens, configuration, etc.)
|
|
20
|
+
*/
|
|
21
|
+
export type OpenAiConfiguration = BaseAiConfiguration & Omit<ChatOpenAIFields, 'model' | 'apiKey'> & {
|
|
22
|
+
provider: 'openai';
|
|
23
|
+
model: OpenAIChatModelId | (string & NonNullable<unknown>);
|
|
24
|
+
};
|
|
25
|
+
export type AiConfiguration = OpenAiConfiguration;
|
|
26
|
+
//# sourceMappingURL=provider.d.ts.map
|
package/dist/provider.js
ADDED
package/dist/router.d.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import type { McpConfiguration } from './mcp-client';
|
|
2
|
-
import type { AiConfiguration
|
|
3
|
-
import type {
|
|
2
|
+
import type { AiConfiguration } from './provider';
|
|
3
|
+
import type { RemoteToolsApiKeys } from './remote-tools';
|
|
4
|
+
import type { RouteArgs } from './schemas/route';
|
|
4
5
|
import type { Logger } from '@forestadmin/datasource-toolkit';
|
|
5
|
-
export type InvokeRemoteToolBody
|
|
6
|
-
|
|
7
|
-
};
|
|
8
|
-
export type Body = DispatchBody | InvokeRemoteToolBody | undefined;
|
|
9
|
-
export type Route = 'ai-query' | 'remote-tools' | 'invoke-remote-tool';
|
|
10
|
-
export type Query = {
|
|
11
|
-
'tool-name'?: string;
|
|
12
|
-
'ai-name'?: string;
|
|
13
|
-
};
|
|
6
|
+
export type { AiQueryArgs, Body, InvokeRemoteToolArgs, InvokeRemoteToolBody, Query, RemoteToolsArgs, RouteArgs, } from './schemas/route';
|
|
7
|
+
export type Route = RouteArgs['route'];
|
|
14
8
|
export type ApiKeys = RemoteToolsApiKeys;
|
|
15
9
|
export declare class Router {
|
|
16
10
|
private readonly localToolsApiKeys?;
|
|
@@ -21,7 +15,7 @@ export declare class Router {
|
|
|
21
15
|
localToolsApiKeys?: ApiKeys;
|
|
22
16
|
logger?: Logger;
|
|
23
17
|
});
|
|
24
|
-
private
|
|
18
|
+
private validateConfigurations;
|
|
25
19
|
/**
|
|
26
20
|
* Route the request to the appropriate handler
|
|
27
21
|
*
|
|
@@ -30,11 +24,10 @@ export declare class Router {
|
|
|
30
24
|
* - invoke-remote-tool: Execute a remote tool by name with the provided inputs
|
|
31
25
|
* - remote-tools: Return the list of available remote tools definitions
|
|
32
26
|
*/
|
|
33
|
-
route(args: {
|
|
34
|
-
body?: Body;
|
|
35
|
-
route: Route;
|
|
36
|
-
query?: Query;
|
|
27
|
+
route(args: RouteArgs & {
|
|
37
28
|
mcpConfigs?: McpConfiguration;
|
|
38
29
|
}): Promise<unknown>;
|
|
30
|
+
private static formatZodError;
|
|
31
|
+
private getAiConfiguration;
|
|
39
32
|
}
|
|
40
33
|
//# sourceMappingURL=router.d.ts.map
|
package/dist/router.js
CHANGED
|
@@ -4,28 +4,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Router = void 0;
|
|
7
|
-
const
|
|
7
|
+
const errors_1 = require("./errors");
|
|
8
8
|
const mcp_client_1 = __importDefault(require("./mcp-client"));
|
|
9
|
+
const provider_dispatcher_1 = require("./provider-dispatcher");
|
|
9
10
|
const remote_tools_1 = require("./remote-tools");
|
|
11
|
+
const route_1 = require("./schemas/route");
|
|
12
|
+
const supported_models_1 = __importDefault(require("./supported-models"));
|
|
10
13
|
class Router {
|
|
11
14
|
constructor(params) {
|
|
12
15
|
this.aiConfigurations = params?.aiConfigurations ?? [];
|
|
13
16
|
this.localToolsApiKeys = params?.localToolsApiKeys;
|
|
14
17
|
this.logger = params?.logger;
|
|
18
|
+
this.validateConfigurations();
|
|
15
19
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const config = this.aiConfigurations.find(c => c.name === aiName);
|
|
21
|
-
if (!config) {
|
|
22
|
-
const fallback = this.aiConfigurations[0];
|
|
23
|
-
this.logger?.('Warn', `AI configuration '${aiName}' not found. Falling back to '${fallback.name}'.`);
|
|
24
|
-
return fallback;
|
|
20
|
+
validateConfigurations() {
|
|
21
|
+
for (const config of this.aiConfigurations) {
|
|
22
|
+
if (!(0, supported_models_1.default)(config.model)) {
|
|
23
|
+
throw new errors_1.AIModelNotSupportedError(config.model);
|
|
25
24
|
}
|
|
26
|
-
return config;
|
|
27
25
|
}
|
|
28
|
-
return this.aiConfigurations[0];
|
|
29
26
|
}
|
|
30
27
|
/**
|
|
31
28
|
* Route the request to the appropriate handler
|
|
@@ -36,36 +33,38 @@ class Router {
|
|
|
36
33
|
* - remote-tools: Return the list of available remote tools definitions
|
|
37
34
|
*/
|
|
38
35
|
async route(args) {
|
|
36
|
+
// Validate input with Zod schema
|
|
37
|
+
const result = route_1.routeArgsSchema.safeParse(args);
|
|
38
|
+
if (!result.success) {
|
|
39
|
+
throw new errors_1.AIBadRequestError(Router.formatZodError(result.error));
|
|
40
|
+
}
|
|
41
|
+
const validatedArgs = result.data;
|
|
39
42
|
let mcpClient;
|
|
40
43
|
try {
|
|
41
44
|
if (args.mcpConfigs) {
|
|
42
45
|
mcpClient = new mcp_client_1.default(args.mcpConfigs, this.logger);
|
|
43
46
|
}
|
|
44
47
|
const remoteTools = new remote_tools_1.RemoteTools(this.localToolsApiKeys ?? {}, await mcpClient?.loadTools());
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (args.route === 'invoke-remote-tool') {
|
|
50
|
-
const toolName = args.query?.['tool-name'];
|
|
51
|
-
if (!toolName) {
|
|
52
|
-
throw new index_1.AIBadRequestError('Missing required query parameter: tool-name');
|
|
48
|
+
switch (validatedArgs.route) {
|
|
49
|
+
case 'ai-query': {
|
|
50
|
+
const aiConfiguration = this.getAiConfiguration(validatedArgs.query?.['ai-name']);
|
|
51
|
+
return await new provider_dispatcher_1.ProviderDispatcher(aiConfiguration, remoteTools).dispatch(validatedArgs.body);
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
case 'invoke-remote-tool':
|
|
54
|
+
return await remoteTools.invokeTool(validatedArgs.query['tool-name'], validatedArgs.body.inputs);
|
|
55
|
+
case 'remote-tools':
|
|
56
|
+
return remoteTools.toolDefinitionsForFrontend;
|
|
57
|
+
/* istanbul ignore next */
|
|
58
|
+
default: {
|
|
59
|
+
// Exhaustive type check - this code never runs at runtime because Zod validation
|
|
60
|
+
// catches unknown routes earlier. However, it provides compile-time safety:
|
|
61
|
+
// if a new route is added to routeArgsSchema, TypeScript will error here with
|
|
62
|
+
// "Type 'NewRouteArgs' is not assignable to type 'never'", forcing the developer
|
|
63
|
+
// to add a corresponding case handler.
|
|
64
|
+
const exhaustiveCheck = validatedArgs;
|
|
65
|
+
return exhaustiveCheck;
|
|
57
66
|
}
|
|
58
|
-
return await remoteTools.invokeTool(toolName, body.inputs);
|
|
59
|
-
}
|
|
60
|
-
if (args.route === 'remote-tools') {
|
|
61
|
-
return remoteTools.toolDefinitionsForFrontend;
|
|
62
67
|
}
|
|
63
|
-
// don't add mcpConfigs to the error message, as it may contain sensitive information
|
|
64
|
-
throw new index_1.AIUnprocessableError(`No action to perform: ${JSON.stringify({
|
|
65
|
-
body: args.body,
|
|
66
|
-
route: args.route,
|
|
67
|
-
query: args.query,
|
|
68
|
-
})}`);
|
|
69
68
|
}
|
|
70
69
|
finally {
|
|
71
70
|
if (mcpClient) {
|
|
@@ -79,6 +78,35 @@ class Router {
|
|
|
79
78
|
}
|
|
80
79
|
}
|
|
81
80
|
}
|
|
81
|
+
static formatZodError(error) {
|
|
82
|
+
return error.issues
|
|
83
|
+
.map(issue => {
|
|
84
|
+
// Handle discriminatedUnion errors with helpful message
|
|
85
|
+
// Zod 4 uses 'invalid_union' code with a 'discriminator' property for these errors
|
|
86
|
+
if (issue.code === 'invalid_union' && issue.discriminator) {
|
|
87
|
+
const validRoutes = route_1.routeArgsSchema.options.map(opt => `'${opt.shape.route.value}'`);
|
|
88
|
+
return `Invalid route. Expected: ${validRoutes.join(', ')}`;
|
|
89
|
+
}
|
|
90
|
+
// Include path for context when available
|
|
91
|
+
const path = issue.path.length > 0 ? `${issue.path.join('.')}: ` : '';
|
|
92
|
+
return `${path}${issue.message}`;
|
|
93
|
+
})
|
|
94
|
+
.join('; ');
|
|
95
|
+
}
|
|
96
|
+
getAiConfiguration(aiName) {
|
|
97
|
+
if (this.aiConfigurations.length === 0)
|
|
98
|
+
return null;
|
|
99
|
+
if (aiName) {
|
|
100
|
+
const config = this.aiConfigurations.find(c => c.name === aiName);
|
|
101
|
+
if (!config) {
|
|
102
|
+
const fallback = this.aiConfigurations[0];
|
|
103
|
+
this.logger?.('Warn', `AI configuration '${aiName}' not found. Falling back to '${fallback.name}'.`);
|
|
104
|
+
return fallback;
|
|
105
|
+
}
|
|
106
|
+
return config;
|
|
107
|
+
}
|
|
108
|
+
return this.aiConfigurations[0];
|
|
109
|
+
}
|
|
82
110
|
}
|
|
83
111
|
exports.Router = Router;
|
|
84
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
112
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFPQSxxQ0FBdUU7QUFDdkUsOERBQXFDO0FBQ3JDLCtEQUEyRDtBQUMzRCxpREFBNkM7QUFDN0MsMkNBQWtEO0FBQ2xELDBFQUF3RDtBQWdCeEQsTUFBYSxNQUFNO0lBS2pCLFlBQVksTUFJWDtRQUNDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxNQUFNLEVBQUUsZ0JBQWdCLElBQUksRUFBRSxDQUFDO1FBQ3ZELElBQUksQ0FBQyxpQkFBaUIsR0FBRyxNQUFNLEVBQUUsaUJBQWlCLENBQUM7UUFDbkQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLEVBQUUsTUFBTSxDQUFDO1FBRTdCLElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO0lBQ2hDLENBQUM7SUFFTyxzQkFBc0I7UUFDNUIsS0FBSyxNQUFNLE1BQU0sSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUMzQyxJQUFJLENBQUMsSUFBQSwwQkFBc0IsRUFBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDMUMsTUFBTSxJQUFJLGlDQUF3QixDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNuRCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFtRDtRQUM3RCxpQ0FBaUM7UUFDakMsTUFBTSxNQUFNLEdBQUcsdUJBQWUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFL0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNwQixNQUFNLElBQUksMEJBQWlCLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUNuRSxDQUFDO1FBRUQsTUFBTSxhQUFhLEdBQUcsTUFB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
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const baseQuerySchema: z.ZodObject<{
|
|
3
|
+
'ai-name': z.ZodOptional<z.ZodString>;
|
|
4
|
+
'tool-name': z.ZodOptional<z.ZodString>;
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
declare const aiQuerySchema: z.ZodObject<{
|
|
7
|
+
route: z.ZodLiteral<"ai-query">;
|
|
8
|
+
query: z.ZodOptional<z.ZodObject<{
|
|
9
|
+
'ai-name': z.ZodOptional<z.ZodString>;
|
|
10
|
+
'tool-name': z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, z.core.$strip>>;
|
|
12
|
+
body: z.ZodObject<{
|
|
13
|
+
messages: z.ZodArray<z.ZodAny>;
|
|
14
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodAny>>;
|
|
15
|
+
tool_choice: z.ZodOptional<z.ZodAny>;
|
|
16
|
+
parallel_tool_calls: z.ZodOptional<z.ZodBoolean>;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
/**
|
|
20
|
+
* Route: invoke-remote-tool
|
|
21
|
+
*
|
|
22
|
+
* Note: inputs uses z.any() because it can be either:
|
|
23
|
+
* - An array of messages (for regular remote tools)
|
|
24
|
+
* - An object of arguments (for MCP tools)
|
|
25
|
+
* Validation happens downstream in the tool implementation.
|
|
26
|
+
*/
|
|
27
|
+
declare const invokeRemoteToolSchema: z.ZodObject<{
|
|
28
|
+
route: z.ZodLiteral<"invoke-remote-tool">;
|
|
29
|
+
query: z.ZodObject<{
|
|
30
|
+
'ai-name': z.ZodOptional<z.ZodString>;
|
|
31
|
+
'tool-name': z.ZodString;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
body: z.ZodObject<{
|
|
34
|
+
inputs: z.ZodAny;
|
|
35
|
+
}, z.core.$strip>;
|
|
36
|
+
}, z.core.$strip>;
|
|
37
|
+
declare const remoteToolsSchema: z.ZodObject<{
|
|
38
|
+
route: z.ZodLiteral<"remote-tools">;
|
|
39
|
+
query: z.ZodOptional<z.ZodObject<{
|
|
40
|
+
'ai-name': z.ZodOptional<z.ZodString>;
|
|
41
|
+
'tool-name': z.ZodOptional<z.ZodString>;
|
|
42
|
+
}, z.core.$strip>>;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
export declare const routeArgsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
45
|
+
route: z.ZodLiteral<"ai-query">;
|
|
46
|
+
query: z.ZodOptional<z.ZodObject<{
|
|
47
|
+
'ai-name': z.ZodOptional<z.ZodString>;
|
|
48
|
+
'tool-name': z.ZodOptional<z.ZodString>;
|
|
49
|
+
}, z.core.$strip>>;
|
|
50
|
+
body: z.ZodObject<{
|
|
51
|
+
messages: z.ZodArray<z.ZodAny>;
|
|
52
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodAny>>;
|
|
53
|
+
tool_choice: z.ZodOptional<z.ZodAny>;
|
|
54
|
+
parallel_tool_calls: z.ZodOptional<z.ZodBoolean>;
|
|
55
|
+
}, z.core.$strip>;
|
|
56
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
57
|
+
route: z.ZodLiteral<"invoke-remote-tool">;
|
|
58
|
+
query: z.ZodObject<{
|
|
59
|
+
'ai-name': z.ZodOptional<z.ZodString>;
|
|
60
|
+
'tool-name': z.ZodString;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
body: z.ZodObject<{
|
|
63
|
+
inputs: z.ZodAny;
|
|
64
|
+
}, z.core.$strip>;
|
|
65
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
66
|
+
route: z.ZodLiteral<"remote-tools">;
|
|
67
|
+
query: z.ZodOptional<z.ZodObject<{
|
|
68
|
+
'ai-name': z.ZodOptional<z.ZodString>;
|
|
69
|
+
'tool-name': z.ZodOptional<z.ZodString>;
|
|
70
|
+
}, z.core.$strip>>;
|
|
71
|
+
}, z.core.$strip>], "route">;
|
|
72
|
+
export type RouteArgs = z.infer<typeof routeArgsSchema>;
|
|
73
|
+
export type AiQueryArgs = z.infer<typeof aiQuerySchema>;
|
|
74
|
+
export type InvokeRemoteToolArgs = z.infer<typeof invokeRemoteToolSchema>;
|
|
75
|
+
export type RemoteToolsArgs = z.infer<typeof remoteToolsSchema>;
|
|
76
|
+
export type DispatchBody = AiQueryArgs['body'];
|
|
77
|
+
export type InvokeRemoteToolBody = InvokeRemoteToolArgs['body'];
|
|
78
|
+
export type Body = DispatchBody | InvokeRemoteToolBody | undefined;
|
|
79
|
+
export type Query = z.infer<typeof baseQuerySchema>;
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.routeArgsSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
// Base query schema with common optional parameters
|
|
6
|
+
const baseQuerySchema = zod_1.z.object({
|
|
7
|
+
'ai-name': zod_1.z.string().optional(),
|
|
8
|
+
'tool-name': zod_1.z.string().optional(),
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Route: ai-query
|
|
12
|
+
*
|
|
13
|
+
* Note: messages, tools, and tool_choice use z.any() because OpenAI types are complex
|
|
14
|
+
* and frequently evolve. Runtime validation happens downstream in the OpenAI SDK.
|
|
15
|
+
* The type casts ensure TypeScript type safety while allowing flexibility.
|
|
16
|
+
*/
|
|
17
|
+
const aiQueryBodySchema = zod_1.z.object({
|
|
18
|
+
messages: zod_1.z.array(zod_1.z.any(), {
|
|
19
|
+
message: 'Missing required body parameter: messages',
|
|
20
|
+
}),
|
|
21
|
+
tools: zod_1.z.array(zod_1.z.any()).optional(),
|
|
22
|
+
tool_choice: zod_1.z.any().optional(),
|
|
23
|
+
parallel_tool_calls: zod_1.z.boolean().optional(),
|
|
24
|
+
}, { message: 'Missing required parameter: body' });
|
|
25
|
+
const aiQuerySchema = zod_1.z.object({
|
|
26
|
+
route: zod_1.z.literal('ai-query'),
|
|
27
|
+
query: baseQuerySchema.optional(),
|
|
28
|
+
body: aiQueryBodySchema,
|
|
29
|
+
});
|
|
30
|
+
// Query schema for invoke-remote-tool (tool-name is required)
|
|
31
|
+
const invokeRemoteToolQuerySchema = zod_1.z.object({
|
|
32
|
+
'ai-name': zod_1.z.string().optional(),
|
|
33
|
+
'tool-name': zod_1.z.string({ message: 'Missing required query parameter: tool-name' }),
|
|
34
|
+
}, { message: 'Missing required parameter: query' });
|
|
35
|
+
/**
|
|
36
|
+
* Route: invoke-remote-tool
|
|
37
|
+
*
|
|
38
|
+
* Note: inputs uses z.any() because it can be either:
|
|
39
|
+
* - An array of messages (for regular remote tools)
|
|
40
|
+
* - An object of arguments (for MCP tools)
|
|
41
|
+
* Validation happens downstream in the tool implementation.
|
|
42
|
+
*/
|
|
43
|
+
const invokeRemoteToolSchema = zod_1.z.object({
|
|
44
|
+
route: zod_1.z.literal('invoke-remote-tool'),
|
|
45
|
+
query: invokeRemoteToolQuerySchema,
|
|
46
|
+
body: zod_1.z.object({
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
48
|
+
inputs: zod_1.z.any().refine((val) => val !== undefined && val !== null, {
|
|
49
|
+
message: 'Missing required body parameter: inputs',
|
|
50
|
+
}),
|
|
51
|
+
}, { message: 'Missing required parameter: body' }),
|
|
52
|
+
});
|
|
53
|
+
// Route: remote-tools (no body required)
|
|
54
|
+
const remoteToolsSchema = zod_1.z.object({
|
|
55
|
+
route: zod_1.z.literal('remote-tools'),
|
|
56
|
+
query: baseQuerySchema.optional(),
|
|
57
|
+
});
|
|
58
|
+
// Discriminated union on 'route'
|
|
59
|
+
exports.routeArgsSchema = zod_1.z.discriminatedUnion('route', [
|
|
60
|
+
aiQuerySchema,
|
|
61
|
+
invokeRemoteToolSchema,
|
|
62
|
+
remoteToolsSchema,
|
|
63
|
+
]);
|
|
64
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2NoZW1hcy9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2QkFBd0I7QUFFeEIsb0RBQW9EO0FBQ3BELE1BQU0sZUFBZSxHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQUM7SUFDL0IsU0FBUyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDaEMsV0FBVyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7Q0FDbkMsQ0FBQyxDQUFDO0FBRUg7Ozs7OztHQU1HO0FBQ0gsTUFBTSxpQkFBaUIsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUNoQztJQUNFLFFBQVEsRUFBRSxPQUFDLENBQUMsS0FBSyxDQUFDLE9BQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtRQUN6QixPQUFPLEVBQUUsMkNBQTJDO0tBQ3JELENBQUM7SUFDRixLQUFLLEVBQUUsT0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUU7SUFDbEMsV0FBVyxFQUFFLE9BQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDL0IsbUJBQW1CLEVBQUUsT0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsRUFBRTtDQUM1QyxFQUNELEVBQUUsT0FBTyxFQUFFLGtDQUFrQyxFQUFFLENBQ2hELENBQUM7QUFFRixNQUFNLGFBQWEsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQzdCLEtBQUssRUFBRSxPQUFDLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQztJQUM1QixLQUFLLEVBQUUsZUFBZSxDQUFDLFFBQVEsRUFBRTtJQUNqQyxJQUFJLEVBQUUsaUJBQWlCO0NBQ3hCLENBQUMsQ0FBQztBQUVILDhEQUE4RDtBQUM5RCxNQUFNLDJCQUEyQixHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQzFDO0lBQ0UsU0FBUyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDaEMsV0FBVyxFQUFFLE9BQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxPQUFPLEVBQUUsNkNBQTZDLEVBQUUsQ0FBQztDQUNsRixFQUNELEVBQUUsT0FBTyxFQUFFLG1DQUFtQyxFQUFFLENBQ2pELENBQUM7QUFFRjs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxzQkFBc0IsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQ3RDLEtBQUssRUFBRSxPQUFDLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUFDO0lBQ3RDLEtBQUssRUFBRSwyQkFBMkI7SUFDbEMsSUFBSSxFQUFFLE9BQUMsQ0FBQyxNQUFNLENBQ1o7UUFDRSw4REFBOEQ7UUFDOUQsTUFBTSxFQUFFLE9BQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFRLEVBQUUsRUFBRSxDQUFDLEdBQUcsS0FBSyxTQUFTLElBQUksR0FBRyxLQUFLLElBQUksRUFBRTtZQUN0RSxPQUFPLEVBQUUseUNBQXlDO1NBQ25ELENBQUM7S0FDSCxFQUNELEVBQUUsT0FBTyxFQUFFLGtDQUFrQyxFQUFFLENBQ2hEO0NBQ0YsQ0FBQyxDQUFDO0FBRUgseUNBQXlDO0FBQ3pDLE1BQU0saUJBQWlCLEdBQUcsT0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNqQyxLQUFLLEVBQUUsT0FBQyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUM7SUFDaEMsS0FBSyxFQUFFLGVBQWUsQ0FBQyxRQUFRLEVBQUU7Q0FDbEMsQ0FBQyxDQUFDO0FBRUgsaUNBQWlDO0FBQ3BCLFFBQUEsZUFBZSxHQUFHLE9BQUMsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLEVBQUU7SUFDM0QsYUFBYTtJQUNiLHNCQUFzQjtJQUN0QixpQkFBaUI7Q0FDbEIsQ0FBQyxDQUFDIn0=
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a model is compatible with Forest Admin AI.
|
|
3
|
+
*
|
|
4
|
+
* Supported models must handle tool calls and the parallel_tool_calls parameter.
|
|
5
|
+
*/
|
|
6
|
+
export default function isModelSupportingTools(model: string): boolean;
|
|
7
|
+
//# sourceMappingURL=supported-models.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = isModelSupportingTools;
|
|
4
|
+
/**
|
|
5
|
+
* OpenAI model prefixes that do NOT support tool calls via the chat completions API.
|
|
6
|
+
*
|
|
7
|
+
* Uses prefix matching: model === prefix OR model.startsWith(prefix + '-')
|
|
8
|
+
*
|
|
9
|
+
* Unknown models are allowed by default.
|
|
10
|
+
* If a model fails the integration test, add it here.
|
|
11
|
+
*
|
|
12
|
+
* @see https://platform.openai.com/docs/guides/function-calling
|
|
13
|
+
*/
|
|
14
|
+
const UNSUPPORTED_MODEL_PREFIXES = [
|
|
15
|
+
// Legacy models
|
|
16
|
+
'gpt-4', // Base gpt-4 doesn't honor tool_choice: required
|
|
17
|
+
'text-davinci',
|
|
18
|
+
'davinci',
|
|
19
|
+
'curie',
|
|
20
|
+
'babbage',
|
|
21
|
+
'ada',
|
|
22
|
+
// O-series reasoning models - don't support parallel_tool_calls
|
|
23
|
+
'o1',
|
|
24
|
+
'o3',
|
|
25
|
+
'o4',
|
|
26
|
+
// Non-chat model families
|
|
27
|
+
'dall-e',
|
|
28
|
+
'whisper',
|
|
29
|
+
'tts',
|
|
30
|
+
'text-embedding',
|
|
31
|
+
'omni-moderation',
|
|
32
|
+
'chatgpt', // chatgpt-4o-latest, chatgpt-image-latest
|
|
33
|
+
'computer-use', // computer-use-preview
|
|
34
|
+
'gpt-image', // gpt-image-1, gpt-image-1.5
|
|
35
|
+
'gpt-realtime', // gpt-realtime, gpt-realtime-mini
|
|
36
|
+
'gpt-audio', // gpt-audio
|
|
37
|
+
'sora', // sora-2, sora-2-pro
|
|
38
|
+
'codex', // codex-mini-latest
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* OpenAI model patterns that do NOT support tool calls.
|
|
42
|
+
* Uses contains matching: model.includes(pattern)
|
|
43
|
+
*/
|
|
44
|
+
const UNSUPPORTED_MODEL_PATTERNS = [
|
|
45
|
+
// Non-chat model variants (can appear in the middle of model names)
|
|
46
|
+
'-realtime',
|
|
47
|
+
'-audio',
|
|
48
|
+
'-transcribe',
|
|
49
|
+
'-tts',
|
|
50
|
+
'-search',
|
|
51
|
+
'-codex',
|
|
52
|
+
'-instruct',
|
|
53
|
+
// Models that only support v1/responses, not v1/chat/completions
|
|
54
|
+
'-pro',
|
|
55
|
+
'-deep-research',
|
|
56
|
+
];
|
|
57
|
+
/**
|
|
58
|
+
* Models that DO support tool calls even though they match an unsupported prefix.
|
|
59
|
+
* These override the UNSUPPORTED_MODEL_PREFIXES list.
|
|
60
|
+
*/
|
|
61
|
+
const SUPPORTED_MODEL_OVERRIDES = ['gpt-4-turbo', 'gpt-4o', 'gpt-4.1'];
|
|
62
|
+
/**
|
|
63
|
+
* Checks if a model is compatible with Forest Admin AI.
|
|
64
|
+
*
|
|
65
|
+
* Supported models must handle tool calls and the parallel_tool_calls parameter.
|
|
66
|
+
*/
|
|
67
|
+
function isModelSupportingTools(model) {
|
|
68
|
+
// Check pattern matches first (contains) - these NEVER support tools
|
|
69
|
+
const matchesUnsupportedPattern = UNSUPPORTED_MODEL_PATTERNS.some(pattern => model.includes(pattern));
|
|
70
|
+
if (matchesUnsupportedPattern)
|
|
71
|
+
return false;
|
|
72
|
+
// Check unsupported prefixes
|
|
73
|
+
const matchesUnsupportedPrefix = UNSUPPORTED_MODEL_PREFIXES.some(prefix => model === prefix || model.startsWith(`${prefix}-`));
|
|
74
|
+
// Check if model is in the supported overrides list
|
|
75
|
+
const isSupportedOverride = SUPPORTED_MODEL_OVERRIDES.some(override => model === override || model.startsWith(`${override}-`));
|
|
76
|
+
// If it matches an unsupported prefix but is not in overrides, reject it
|
|
77
|
+
if (matchesUnsupportedPrefix && !isSupportedOverride)
|
|
78
|
+
return false;
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VwcG9ydGVkLW1vZGVscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9zdXBwb3J0ZWQtbW9kZWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBa0VBLHlDQXFCQztBQXZGRDs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLDBCQUEwQixHQUFHO0lBQ2pDLGdCQUFnQjtJQUNoQixPQUFPLEVBQUUsaURBQWlEO0lBQzFELGNBQWM7SUFDZCxTQUFTO0lBQ1QsT0FBTztJQUNQLFNBQVM7SUFDVCxLQUFLO0lBQ0wsZ0VBQWdFO0lBQ2hFLElBQUk7SUFDSixJQUFJO0lBQ0osSUFBSTtJQUNKLDBCQUEwQjtJQUMxQixRQUFRO0lBQ1IsU0FBUztJQUNULEtBQUs7SUFDTCxnQkFBZ0I7SUFDaEIsaUJBQWlCO0lBQ2pCLFNBQVMsRUFBRSwwQ0FBMEM7SUFDckQsY0FBYyxFQUFFLHVCQUF1QjtJQUN2QyxXQUFXLEVBQUUsNkJBQTZCO0lBQzFDLGNBQWMsRUFBRSxrQ0FBa0M7SUFDbEQsV0FBVyxFQUFFLFlBQVk7SUFDekIsTUFBTSxFQUFFLHFCQUFxQjtJQUM3QixPQUFPLEVBQUUsb0JBQW9CO0NBQzlCLENBQUM7QUFFRjs7O0dBR0c7QUFDSCxNQUFNLDBCQUEwQixHQUFHO0lBQ2pDLG9FQUFvRTtJQUNwRSxXQUFXO0lBQ1gsUUFBUTtJQUNSLGFBQWE7SUFDYixNQUFNO0lBQ04sU0FBUztJQUNULFFBQVE7SUFDUixXQUFXO0lBQ1gsaUVBQWlFO0lBQ2pFLE1BQU07SUFDTixnQkFBZ0I7Q0FDakIsQ0FBQztBQUVGOzs7R0FHRztBQUNILE1BQU0seUJBQXlCLEdBQUcsQ0FBQyxhQUFhLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBRXZFOzs7O0dBSUc7QUFDSCxTQUF3QixzQkFBc0IsQ0FBQyxLQUFhO0lBQzFELHFFQUFxRTtJQUNyRSxNQUFNLHlCQUF5QixHQUFHLDBCQUEwQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUMxRSxLQUFLLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUN4QixDQUFDO0lBQ0YsSUFBSSx5QkFBeUI7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUU1Qyw2QkFBNkI7SUFDN0IsTUFBTSx3QkFBd0IsR0FBRywwQkFBMEIsQ0FBQyxJQUFJLENBQzlELE1BQU0sQ0FBQyxFQUFFLENBQUMsS0FBSyxLQUFLLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsTUFBTSxHQUFHLENBQUMsQ0FDN0QsQ0FBQztJQUVGLG9EQUFvRDtJQUNwRCxNQUFNLG1CQUFtQixHQUFHLHlCQUF5QixDQUFDLElBQUksQ0FDeEQsUUFBUSxDQUFDLEVBQUUsQ0FBQyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxVQUFVLENBQUMsR0FBRyxRQUFRLEdBQUcsQ0FBQyxDQUNuRSxDQUFDO0lBRUYseUVBQXlFO0lBQ3pFLElBQUksd0JBQXdCLElBQUksQ0FBQyxtQkFBbUI7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUVuRSxPQUFPLElBQUksQ0FBQztBQUNkLENBQUMifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestadmin/ai-proxy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"@langchain/core": "1.1.15",
|
|
18
18
|
"@langchain/langgraph": "^1.1.0",
|
|
19
19
|
"@langchain/mcp-adapters": "1.1.1",
|
|
20
|
-
"@langchain/openai": "1.2.
|
|
20
|
+
"@langchain/openai": "1.2.5",
|
|
21
21
|
"zod": "^4.3.5"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|