@forestadmin/ai-proxy 1.4.3 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/anthropic-adapter.d.ts +27 -0
- package/dist/anthropic-adapter.js +51 -0
- package/dist/create-ai-provider.d.ts +4 -0
- package/dist/create-ai-provider.js +34 -0
- package/dist/errors.d.ts +13 -19
- package/dist/errors.js +19 -33
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -1
- package/dist/langchain-adapter.d.ts +45 -0
- package/dist/langchain-adapter.js +126 -0
- package/dist/provider-dispatcher.d.ts +19 -3
- package/dist/provider-dispatcher.js +98 -27
- package/dist/provider.d.ts +16 -5
- package/dist/router.js +5 -5
- package/dist/schemas/route.d.ts +4 -0
- package/dist/schemas/route.js +1 -1
- package/dist/supported-models.d.ts +2 -6
- package/dist/supported-models.js +35 -38
- package/package.json +3 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { OpenAIMessage } from './langchain-adapter';
|
|
2
|
+
import type { ChatCompletionTool, ChatCompletionToolChoice } from './provider';
|
|
3
|
+
import type { ChatAnthropic } from '@langchain/anthropic';
|
|
4
|
+
import type { BaseMessage } from '@langchain/core/messages';
|
|
5
|
+
export default class AnthropicAdapter {
|
|
6
|
+
static convertMessages(messages: OpenAIMessage[]): BaseMessage[];
|
|
7
|
+
/** Cast `as string` works around LangChain's AnthropicToolChoice missing `disable_parallel_tool_use`. */
|
|
8
|
+
static bindTools(model: ChatAnthropic, tools: ChatCompletionTool[], { toolChoice, parallelToolCalls, }: {
|
|
9
|
+
toolChoice?: ChatCompletionToolChoice;
|
|
10
|
+
parallelToolCalls?: boolean;
|
|
11
|
+
}): ChatAnthropic;
|
|
12
|
+
/**
|
|
13
|
+
* Convert OpenAI tool_choice to Anthropic format, applying parallel tool restriction.
|
|
14
|
+
*
|
|
15
|
+
* Converts to LangChain format first, then applies `disable_parallel_tool_use`
|
|
16
|
+
* when `parallelToolCalls` is explicitly `false` (not just falsy — `undefined` means
|
|
17
|
+
* no restriction).
|
|
18
|
+
*/
|
|
19
|
+
private static convertToolChoice;
|
|
20
|
+
/**
|
|
21
|
+
* Merge all system messages into a single one placed first.
|
|
22
|
+
*
|
|
23
|
+
* Anthropic only allows a single system message at the beginning of the conversation.
|
|
24
|
+
*/
|
|
25
|
+
private static mergeSystemMessages;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=anthropic-adapter.d.ts.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const langchain_adapter_1 = require("./langchain-adapter");
|
|
4
|
+
class AnthropicAdapter {
|
|
5
|
+
static convertMessages(messages) {
|
|
6
|
+
return langchain_adapter_1.LangChainAdapter.convertMessages(AnthropicAdapter.mergeSystemMessages(messages));
|
|
7
|
+
}
|
|
8
|
+
/** Cast `as string` works around LangChain's AnthropicToolChoice missing `disable_parallel_tool_use`. */
|
|
9
|
+
static bindTools(model, tools, { toolChoice, parallelToolCalls, }) {
|
|
10
|
+
return model.bindTools(tools, {
|
|
11
|
+
tool_choice: AnthropicAdapter.convertToolChoice({ toolChoice, parallelToolCalls }),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Convert OpenAI tool_choice to Anthropic format, applying parallel tool restriction.
|
|
16
|
+
*
|
|
17
|
+
* Converts to LangChain format first, then applies `disable_parallel_tool_use`
|
|
18
|
+
* when `parallelToolCalls` is explicitly `false` (not just falsy — `undefined` means
|
|
19
|
+
* no restriction).
|
|
20
|
+
*/
|
|
21
|
+
static convertToolChoice({ toolChoice, parallelToolCalls, } = {}) {
|
|
22
|
+
const base = langchain_adapter_1.LangChainAdapter.convertToolChoice(toolChoice);
|
|
23
|
+
if (parallelToolCalls !== false)
|
|
24
|
+
return base;
|
|
25
|
+
// Anthropic requires object form to set disable_parallel_tool_use
|
|
26
|
+
if (base === undefined || base === 'auto') {
|
|
27
|
+
return { type: 'auto', disable_parallel_tool_use: true };
|
|
28
|
+
}
|
|
29
|
+
if (base === 'any') {
|
|
30
|
+
return { type: 'any', disable_parallel_tool_use: true };
|
|
31
|
+
}
|
|
32
|
+
if (base === 'none')
|
|
33
|
+
return 'none';
|
|
34
|
+
return { ...base, disable_parallel_tool_use: true };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Merge all system messages into a single one placed first.
|
|
38
|
+
*
|
|
39
|
+
* Anthropic only allows a single system message at the beginning of the conversation.
|
|
40
|
+
*/
|
|
41
|
+
static mergeSystemMessages(messages) {
|
|
42
|
+
const systemContents = messages.filter(m => m.role === 'system').map(m => m.content || '');
|
|
43
|
+
if (systemContents.length <= 1)
|
|
44
|
+
return messages;
|
|
45
|
+
const merged = { role: 'system', content: systemContents.join('\n\n') };
|
|
46
|
+
const nonSystem = messages.filter(m => m.role !== 'system');
|
|
47
|
+
return [merged, ...nonSystem];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.default = AnthropicAdapter;
|
|
51
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW50aHJvcGljLWFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYW50aHJvcGljLWFkYXB0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFLQSwyREFBdUQ7QUFldkQsTUFBcUIsZ0JBQWdCO0lBQ25DLE1BQU0sQ0FBQyxlQUFlLENBQUMsUUFBeUI7UUFDOUMsT0FBTyxvQ0FBZ0IsQ0FBQyxlQUFlLENBQUMsZ0JBQWdCLENBQUMsbUJBQW1CLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUMxRixDQUFDO0lBRUQseUdBQXlHO0lBQ3pHLE1BQU0sQ0FBQyxTQUFTLENBQ2QsS0FBb0IsRUFDcEIsS0FBMkIsRUFDM0IsRUFDRSxVQUFVLEVBQ1YsaUJBQWlCLEdBQ3NEO1FBRXpFLE9BQU8sS0FBSyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUU7WUFDNUIsV0FBVyxFQUFFLGdCQUFnQixDQUFDLGlCQUFpQixDQUFDLEVBQUUsVUFBVSxFQUFFLGlCQUFpQixFQUFFLENBQVc7U0FDN0YsQ0FBa0IsQ0FBQztJQUN0QixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ssTUFBTSxDQUFDLGlCQUFpQixDQUFDLEVBQy9CLFVBQVUsRUFDVixpQkFBaUIsTUFJZixFQUFFO1FBQ0osTUFBTSxJQUFJLEdBQUcsb0NBQWdCLENBQUMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLENBQUM7UUFFNUQsSUFBSSxpQkFBaUIsS0FBSyxLQUFLO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFFN0Msa0VBQWtFO1FBQ2xFLElBQUksSUFBSSxLQUFLLFNBQVMsSUFBSSxJQUFJLEtBQUssTUFBTSxFQUFFLENBQUM7WUFDMUMsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUseUJBQXlCLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDM0QsQ0FBQztRQUVELElBQUksSUFBSSxLQUFLLEtBQUssRUFBRSxDQUFDO1lBQ25CLE9BQU8sRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLHlCQUF5QixFQUFFLElBQUksRUFBRSxDQUFDO1FBQzFELENBQUM7UUFFRCxJQUFJLElBQUksS0FBSyxNQUFNO1lBQUUsT0FBTyxNQUFNLENBQUM7UUFFbkMsT0FBTyxFQUFFLEdBQUcsSUFBSSxFQUFFLHlCQUF5QixFQUFFLElBQUksRUFBRSxDQUFDO0lBQ3RELENBQUM7SUFFRDs7OztPQUlHO0lBQ0ssTUFBTSxDQUFDLG1CQUFtQixDQUFDLFFBQXlCO1FBQzFELE1BQU0sY0FBYyxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLFFBQVEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDLENBQUM7UUFFM0YsSUFBSSxjQUFjLENBQUMsTUFBTSxJQUFJLENBQUM7WUFBRSxPQUFPLFFBQVEsQ0FBQztRQUVoRCxNQUFNLE1BQU0sR0FBa0IsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxjQUFjLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDdkYsTUFBTSxTQUFTLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDLENBQUM7UUFFNUQsT0FBTyxDQUFDLE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBQ2hDLENBQUM7Q0FDRjtBQWxFRCxtQ0FrRUMifQ==
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAiProvider = createAiProvider;
|
|
4
|
+
const oauth_token_injector_1 = require("./oauth-token-injector");
|
|
5
|
+
const router_1 = require("./router");
|
|
6
|
+
function resolveMcpConfigs(args) {
|
|
7
|
+
const tokensByMcpServerName = args.headers
|
|
8
|
+
? (0, oauth_token_injector_1.extractMcpOauthTokensFromHeaders)(args.headers)
|
|
9
|
+
: undefined;
|
|
10
|
+
return (0, oauth_token_injector_1.injectOauthTokens)({
|
|
11
|
+
mcpConfigs: args.mcpServerConfigs,
|
|
12
|
+
tokensByMcpServerName,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
// eslint-disable-next-line import/prefer-default-export
|
|
16
|
+
function createAiProvider(config) {
|
|
17
|
+
return {
|
|
18
|
+
providers: [{ name: config.name, provider: config.provider, model: config.model }],
|
|
19
|
+
init(logger) {
|
|
20
|
+
const router = new router_1.Router({ aiConfigurations: [config], logger });
|
|
21
|
+
return {
|
|
22
|
+
// Cast is safe: AiRouter.route accepts any string, but Router validates
|
|
23
|
+
// it at runtime via Zod against the allowed literal union (RouterRouteArgs).
|
|
24
|
+
route: args => router.route({
|
|
25
|
+
route: args.route,
|
|
26
|
+
body: args.body,
|
|
27
|
+
query: args.query,
|
|
28
|
+
mcpConfigs: resolveMcpConfigs(args),
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLWFpLXByb3ZpZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NyZWF0ZS1haS1wcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQW9CQSw0Q0FtQkM7QUFsQ0QsaUVBQTZGO0FBQzdGLHFDQUFrQztBQUVsQyxTQUFTLGlCQUFpQixDQUFDLElBQXNDO0lBQy9ELE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDLE9BQU87UUFDeEMsQ0FBQyxDQUFDLElBQUEsdURBQWdDLEVBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUNoRCxDQUFDLENBQUMsU0FBUyxDQUFDO0lBRWQsT0FBTyxJQUFBLHdDQUFpQixFQUFDO1FBQ3ZCLFVBQVUsRUFBRSxJQUFJLENBQUMsZ0JBQWdEO1FBQ2pFLHFCQUFxQjtLQUN0QixDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsd0RBQXdEO0FBQ3hELFNBQWdCLGdCQUFnQixDQUFDLE1BQXVCO0lBQ3RELE9BQU87UUFDTCxTQUFTLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDbEYsSUFBSSxDQUFDLE1BQU07WUFDVCxNQUFNLE1BQU0sR0FBRyxJQUFJLGVBQU0sQ0FBQyxFQUFFLGdCQUFnQixFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztZQUVsRSxPQUFPO2dCQUNMLHdFQUF3RTtnQkFDeEUsNkVBQTZFO2dCQUM3RSxLQUFLLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FDWixNQUFNLENBQUMsS0FBSyxDQUFDO29CQUNYLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSztvQkFDakIsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJO29CQUNmLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSztvQkFDakIsVUFBVSxFQUFFLGlCQUFpQixDQUFDLElBQUksQ0FBQztpQkFDakIsQ0FBQzthQUN4QixDQUFDO1FBQ0osQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDIn0=
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,36 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* All custom errors must extend the AIError class.
|
|
6
|
-
* This inheritance is crucial for proper error translation
|
|
7
|
-
* and consistent handling throughout the system.
|
|
8
|
-
* -------------------------------------
|
|
9
|
-
* -------------------------------------
|
|
10
|
-
* -------------------------------------
|
|
2
|
+
* All custom AI errors extend HTTP-status error classes (BadRequestError, NotFoundError,
|
|
3
|
+
* UnprocessableError) from datasource-toolkit. This allows the agent's error middleware
|
|
4
|
+
* to map them to their natural HTTP status codes automatically.
|
|
11
5
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
constructor(message: string
|
|
6
|
+
import { BadRequestError, NotFoundError, UnprocessableError } from '@forestadmin/datasource-toolkit';
|
|
7
|
+
export declare class AIError extends UnprocessableError {
|
|
8
|
+
constructor(message: string);
|
|
15
9
|
}
|
|
16
|
-
export declare class AIBadRequestError extends
|
|
10
|
+
export declare class AIBadRequestError extends BadRequestError {
|
|
17
11
|
constructor(message: string);
|
|
18
12
|
}
|
|
19
13
|
export declare class AIModelNotSupportedError extends AIBadRequestError {
|
|
20
14
|
constructor(model: string);
|
|
21
15
|
}
|
|
22
|
-
export declare class AINotFoundError extends
|
|
16
|
+
export declare class AINotFoundError extends NotFoundError {
|
|
23
17
|
constructor(message: string);
|
|
24
18
|
}
|
|
25
|
-
export declare class AIUnprocessableError extends
|
|
26
|
-
|
|
19
|
+
export declare class AIUnprocessableError extends UnprocessableError {
|
|
20
|
+
readonly cause?: Error;
|
|
21
|
+
constructor(message: string, options?: {
|
|
22
|
+
cause?: Error;
|
|
23
|
+
});
|
|
27
24
|
}
|
|
28
25
|
export declare class AINotConfiguredError extends AIError {
|
|
29
26
|
constructor(message?: string);
|
|
30
27
|
}
|
|
31
|
-
export declare class OpenAIUnprocessableError extends AIUnprocessableError {
|
|
32
|
-
constructor(message: string);
|
|
33
|
-
}
|
|
34
28
|
export declare class AIToolUnprocessableError extends AIUnprocessableError {
|
|
35
29
|
constructor(message: string);
|
|
36
30
|
}
|
package/dist/errors.js
CHANGED
|
@@ -1,32 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* All custom errors must extend the AIError class.
|
|
7
|
-
* This inheritance is crucial for proper error translation
|
|
8
|
-
* and consistent handling throughout the system.
|
|
9
|
-
* -------------------------------------
|
|
10
|
-
* -------------------------------------
|
|
11
|
-
* -------------------------------------
|
|
3
|
+
* All custom AI errors extend HTTP-status error classes (BadRequestError, NotFoundError,
|
|
4
|
+
* UnprocessableError) from datasource-toolkit. This allows the agent's error middleware
|
|
5
|
+
* to map them to their natural HTTP status codes automatically.
|
|
12
6
|
*/
|
|
13
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.McpConfigError = exports.McpConflictError = exports.McpConnectionError = exports.McpError = exports.AIToolNotFoundError = exports.AIToolUnprocessableError = exports.
|
|
8
|
+
exports.McpConfigError = exports.McpConflictError = exports.McpConnectionError = exports.McpError = exports.AIToolNotFoundError = exports.AIToolUnprocessableError = exports.AINotConfiguredError = exports.AIUnprocessableError = exports.AINotFoundError = exports.AIModelNotSupportedError = exports.AIBadRequestError = exports.AIError = void 0;
|
|
15
9
|
// eslint-disable-next-line max-classes-per-file
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
throw new RangeError(`Invalid HTTP status code: ${status}`);
|
|
20
|
-
}
|
|
10
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
11
|
+
class AIError extends datasource_toolkit_1.UnprocessableError {
|
|
12
|
+
constructor(message) {
|
|
21
13
|
super(message);
|
|
22
14
|
this.name = 'AIError';
|
|
23
|
-
this.status = status;
|
|
24
15
|
}
|
|
25
16
|
}
|
|
26
17
|
exports.AIError = AIError;
|
|
27
|
-
class AIBadRequestError extends
|
|
18
|
+
class AIBadRequestError extends datasource_toolkit_1.BadRequestError {
|
|
28
19
|
constructor(message) {
|
|
29
|
-
super(message
|
|
20
|
+
super(message);
|
|
30
21
|
this.name = 'AIBadRequestError';
|
|
31
22
|
}
|
|
32
23
|
}
|
|
@@ -38,38 +29,33 @@ class AIModelNotSupportedError extends AIBadRequestError {
|
|
|
38
29
|
}
|
|
39
30
|
}
|
|
40
31
|
exports.AIModelNotSupportedError = AIModelNotSupportedError;
|
|
41
|
-
class AINotFoundError extends
|
|
32
|
+
class AINotFoundError extends datasource_toolkit_1.NotFoundError {
|
|
42
33
|
constructor(message) {
|
|
43
|
-
super(message
|
|
34
|
+
super(message);
|
|
44
35
|
this.name = 'AINotFoundError';
|
|
45
36
|
}
|
|
46
37
|
}
|
|
47
38
|
exports.AINotFoundError = AINotFoundError;
|
|
48
|
-
class AIUnprocessableError extends
|
|
49
|
-
constructor(message) {
|
|
50
|
-
super(message
|
|
39
|
+
class AIUnprocessableError extends datasource_toolkit_1.UnprocessableError {
|
|
40
|
+
constructor(message, options) {
|
|
41
|
+
super(message);
|
|
51
42
|
this.name = 'AIUnprocessableError';
|
|
43
|
+
if (options?.cause)
|
|
44
|
+
this.cause = options.cause;
|
|
52
45
|
}
|
|
53
46
|
}
|
|
54
47
|
exports.AIUnprocessableError = AIUnprocessableError;
|
|
55
48
|
class AINotConfiguredError extends AIError {
|
|
56
49
|
constructor(message = 'AI is not configured') {
|
|
57
|
-
super(message
|
|
50
|
+
super(message);
|
|
58
51
|
this.name = 'AINotConfiguredError';
|
|
59
52
|
}
|
|
60
53
|
}
|
|
61
54
|
exports.AINotConfiguredError = AINotConfiguredError;
|
|
62
|
-
class OpenAIUnprocessableError extends AIUnprocessableError {
|
|
63
|
-
constructor(message) {
|
|
64
|
-
super(message);
|
|
65
|
-
this.name = 'OpenAIError';
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
exports.OpenAIUnprocessableError = OpenAIUnprocessableError;
|
|
69
55
|
class AIToolUnprocessableError extends AIUnprocessableError {
|
|
70
56
|
constructor(message) {
|
|
71
57
|
super(message);
|
|
72
|
-
this.name = '
|
|
58
|
+
this.name = 'AIToolUnprocessableError';
|
|
73
59
|
}
|
|
74
60
|
}
|
|
75
61
|
exports.AIToolUnprocessableError = AIToolUnprocessableError;
|
|
@@ -108,4 +94,4 @@ class McpConfigError extends McpError {
|
|
|
108
94
|
}
|
|
109
95
|
}
|
|
110
96
|
exports.McpConfigError = McpConfigError;
|
|
111
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
97
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7O0FBRUgsZ0RBQWdEO0FBQ2hELHdFQUl5QztBQUV6QyxNQUFhLE9BQVEsU0FBUSx1Q0FBa0I7SUFDN0MsWUFBWSxPQUFlO1FBQ3pCLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNmLElBQUksQ0FBQyxJQUFJLEdBQUcsU0FBUyxDQUFDO0lBQ3hCLENBQUM7Q0FDRjtBQUxELDBCQUtDO0FBRUQsTUFBYSxpQkFBa0IsU0FBUSxvQ0FBZTtJQUNwRCxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxtQkFBbUIsQ0FBQztJQUNsQyxDQUFDO0NBQ0Y7QUFMRCw4Q0FLQztBQUVELE1BQWEsd0JBQXlCLFNBQVEsaUJBQWlCO0lBQzdELFlBQVksS0FBYTtRQUN2QixLQUFLLENBQ0gsVUFBVSxLQUFLLDhFQUE4RSxDQUM5RixDQUFDO1FBQ0YsSUFBSSxDQUFDLElBQUksR0FBRywwQkFBMEIsQ0FBQztJQUN6QyxDQUFDO0NBQ0Y7QUFQRCw0REFPQztBQUVELE1BQWEsZUFBZ0IsU0FBUSxrQ0FBYTtJQUNoRCxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxpQkFBaUIsQ0FBQztJQUNoQyxDQUFDO0NBQ0Y7QUFMRCwwQ0FLQztBQUVELE1BQWEsb0JBQXFCLFNBQVEsdUNBQWtCO0lBRzFELFlBQVksT0FBZSxFQUFFLE9BQTJCO1FBQ3RELEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNmLElBQUksQ0FBQyxJQUFJLEdBQUcsc0JBQXNCLENBQUM7UUFDbkMsSUFBSSxPQUFPLEVBQUUsS0FBSztZQUFFLElBQUksQ0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQztJQUNqRCxDQUFDO0NBQ0Y7QUFSRCxvREFRQztBQUVELE1BQWEsb0JBQXFCLFNBQVEsT0FBTztJQUMvQyxZQUFZLE9BQU8sR0FBRyxzQkFBc0I7UUFDMUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxzQkFBc0IsQ0FBQztJQUNyQyxDQUFDO0NBQ0Y7QUFMRCxvREFLQztBQUVELE1BQWEsd0JBQXlCLFNBQVEsb0JBQW9CO0lBQ2hFLFlBQVksT0FBZTtRQUN6QixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLDBCQUEwQixDQUFDO0lBQ3pDLENBQUM7Q0FDRjtBQUxELDREQUtDO0FBRUQsTUFBYSxtQkFBb0IsU0FBUSxlQUFlO0lBQ3RELFlBQVksT0FBZTtRQUN6QixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLHFCQUFxQixDQUFDO0lBQ3BDLENBQUM7Q0FDRjtBQUxELGtEQUtDO0FBRUQsTUFBYSxRQUFTLFNBQVEsT0FBTztJQUNuQyxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxVQUFVLENBQUM7SUFDekIsQ0FBQztDQUNGO0FBTEQsNEJBS0M7QUFFRCxNQUFhLGtCQUFtQixTQUFRLFFBQVE7SUFDOUMsWUFBWSxPQUFlO1FBQ3pCLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNmLElBQUksQ0FBQyxJQUFJLEdBQUcsb0JBQW9CLENBQUM7SUFDbkMsQ0FBQztDQUNGO0FBTEQsZ0RBS0M7QUFFRCxNQUFhLGdCQUFpQixTQUFRLFFBQVE7SUFDNUMsWUFBWSxVQUFrQjtRQUM1QixLQUFLLENBQUMsSUFBSSxVQUFVLG1DQUFtQyxDQUFDLENBQUM7UUFDekQsSUFBSSxDQUFDLElBQUksR0FBRyxrQkFBa0IsQ0FBQztJQUNqQyxDQUFDO0NBQ0Y7QUFMRCw0Q0FLQztBQUVELE1BQWEsY0FBZSxTQUFRLFFBQVE7SUFDMUMsWUFBWSxPQUFlO1FBQ3pCLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNmLElBQUksQ0FBQyxJQUFJLEdBQUcsZ0JBQWdCLENBQUM7SUFDL0IsQ0FBQztDQUNGO0FBTEQsd0NBS0MifQ==
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { McpConfiguration } from './mcp-client';
|
|
2
|
+
export { createAiProvider } from './create-ai-provider';
|
|
3
|
+
export { default as ProviderDispatcher } from './provider-dispatcher';
|
|
2
4
|
export * from './provider-dispatcher';
|
|
3
5
|
export * from './remote-tools';
|
|
4
6
|
export * from './router';
|
package/dist/index.js
CHANGED
|
@@ -17,8 +17,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.ProviderDispatcher = exports.createAiProvider = void 0;
|
|
20
21
|
exports.validMcpConfigurationOrThrow = validMcpConfigurationOrThrow;
|
|
21
22
|
const mcp_config_checker_1 = __importDefault(require("./mcp-config-checker"));
|
|
23
|
+
var create_ai_provider_1 = require("./create-ai-provider");
|
|
24
|
+
Object.defineProperty(exports, "createAiProvider", { enumerable: true, get: function () { return create_ai_provider_1.createAiProvider; } });
|
|
25
|
+
var provider_dispatcher_1 = require("./provider-dispatcher");
|
|
26
|
+
Object.defineProperty(exports, "ProviderDispatcher", { enumerable: true, get: function () { return __importDefault(provider_dispatcher_1).default; } });
|
|
22
27
|
__exportStar(require("./provider-dispatcher"), exports);
|
|
23
28
|
__exportStar(require("./remote-tools"), exports);
|
|
24
29
|
__exportStar(require("./router"), exports);
|
|
@@ -28,4 +33,4 @@ __exportStar(require("./errors"), exports);
|
|
|
28
33
|
function validMcpConfigurationOrThrow(mcpConfig) {
|
|
29
34
|
return mcp_config_checker_1.default.check(mcpConfig);
|
|
30
35
|
}
|
|
31
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFhQSxvRUFFQztBQWJELDhFQUFvRDtBQUVwRCwyREFBd0Q7QUFBL0Msc0hBQUEsZ0JBQWdCLE9BQUE7QUFDekIsNkRBQXNFO0FBQTdELDBJQUFBLE9BQU8sT0FBc0I7QUFDdEMsd0RBQXNDO0FBQ3RDLGlEQUErQjtBQUMvQiwyQ0FBeUI7QUFDekIsK0NBQTZCO0FBQzdCLHlEQUF1QztBQUN2QywyQ0FBeUI7QUFFekIsU0FBZ0IsNEJBQTRCLENBQUMsU0FBMkI7SUFDdEUsT0FBTyw0QkFBZ0IsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7QUFDM0MsQ0FBQyJ9
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ChatCompletionResponse, ChatCompletionToolChoice } from './provider';
|
|
2
|
+
import type { BaseMessage } from '@langchain/core/messages';
|
|
3
|
+
import { AIMessage } from '@langchain/core/messages';
|
|
4
|
+
interface OpenAISystemMessage {
|
|
5
|
+
role: 'system';
|
|
6
|
+
content: string | null;
|
|
7
|
+
}
|
|
8
|
+
interface OpenAIUserMessage {
|
|
9
|
+
role: 'user';
|
|
10
|
+
content: string | null;
|
|
11
|
+
}
|
|
12
|
+
interface OpenAIAssistantMessage {
|
|
13
|
+
role: 'assistant';
|
|
14
|
+
content: string | null;
|
|
15
|
+
tool_calls?: Array<{
|
|
16
|
+
id: string;
|
|
17
|
+
function: {
|
|
18
|
+
name: string;
|
|
19
|
+
arguments: string;
|
|
20
|
+
};
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
interface OpenAIToolMessage {
|
|
24
|
+
role: 'tool';
|
|
25
|
+
content: string | null;
|
|
26
|
+
tool_call_id: string;
|
|
27
|
+
}
|
|
28
|
+
export type OpenAIMessage = OpenAISystemMessage | OpenAIUserMessage | OpenAIAssistantMessage | OpenAIToolMessage;
|
|
29
|
+
export type LangChainToolChoice = 'auto' | 'any' | 'none' | {
|
|
30
|
+
type: 'tool';
|
|
31
|
+
name: string;
|
|
32
|
+
} | undefined;
|
|
33
|
+
/** Handles generic format conversions between OpenAI and LangChain. */
|
|
34
|
+
export declare class LangChainAdapter {
|
|
35
|
+
/** Convert OpenAI-format messages to LangChain messages. */
|
|
36
|
+
static convertMessages(messages: OpenAIMessage[]): BaseMessage[];
|
|
37
|
+
/** Convert a LangChain AIMessage to an OpenAI-compatible ChatCompletionResponse. */
|
|
38
|
+
static convertResponse(response: AIMessage, modelName: string | null): ChatCompletionResponse;
|
|
39
|
+
/** Convert OpenAI tool_choice to LangChain format. */
|
|
40
|
+
static convertToolChoice(toolChoice: ChatCompletionToolChoice | undefined): LangChainToolChoice;
|
|
41
|
+
private static extractTextContent;
|
|
42
|
+
private static parseToolArguments;
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=langchain-adapter.d.ts.map
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LangChainAdapter = void 0;
|
|
7
|
+
const messages_1 = require("@langchain/core/messages");
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const errors_1 = require("./errors");
|
|
10
|
+
/** Handles generic format conversions between OpenAI and LangChain. */
|
|
11
|
+
class LangChainAdapter {
|
|
12
|
+
/** Convert OpenAI-format messages to LangChain messages. */
|
|
13
|
+
static convertMessages(messages) {
|
|
14
|
+
const result = [];
|
|
15
|
+
for (const msg of messages) {
|
|
16
|
+
switch (msg.role) {
|
|
17
|
+
case 'system':
|
|
18
|
+
result.push(new messages_1.SystemMessage(msg.content || ''));
|
|
19
|
+
break;
|
|
20
|
+
case 'user':
|
|
21
|
+
result.push(new messages_1.HumanMessage(msg.content || ''));
|
|
22
|
+
break;
|
|
23
|
+
case 'assistant':
|
|
24
|
+
if (msg.tool_calls) {
|
|
25
|
+
result.push(new messages_1.AIMessage({
|
|
26
|
+
content: msg.content || '',
|
|
27
|
+
tool_calls: msg.tool_calls.map(tc => ({
|
|
28
|
+
id: tc.id,
|
|
29
|
+
name: tc.function.name,
|
|
30
|
+
args: LangChainAdapter.parseToolArguments(tc.function.name, tc.function.arguments),
|
|
31
|
+
})),
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
result.push(new messages_1.AIMessage(msg.content || ''));
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
case 'tool':
|
|
39
|
+
if (!msg.tool_call_id) {
|
|
40
|
+
throw new errors_1.AIBadRequestError('Tool message is missing required "tool_call_id" field.');
|
|
41
|
+
}
|
|
42
|
+
result.push(new messages_1.ToolMessage({
|
|
43
|
+
content: msg.content || '',
|
|
44
|
+
tool_call_id: msg.tool_call_id,
|
|
45
|
+
}));
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
throw new errors_1.AIBadRequestError(`Unsupported message role '${msg.role}'. Expected: system, user, assistant, or tool.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
/** Convert a LangChain AIMessage to an OpenAI-compatible ChatCompletionResponse. */
|
|
54
|
+
static convertResponse(response, modelName) {
|
|
55
|
+
const toolCalls = response.tool_calls?.map(tc => ({
|
|
56
|
+
id: tc.id || `call_${crypto_1.default.randomUUID()}`,
|
|
57
|
+
type: 'function',
|
|
58
|
+
function: {
|
|
59
|
+
name: tc.name,
|
|
60
|
+
arguments: JSON.stringify(tc.args),
|
|
61
|
+
},
|
|
62
|
+
}));
|
|
63
|
+
const usageMetadata = response.usage_metadata;
|
|
64
|
+
return {
|
|
65
|
+
id: response.id || `msg_${crypto_1.default.randomUUID()}`,
|
|
66
|
+
object: 'chat.completion',
|
|
67
|
+
created: Math.floor(Date.now() / 1000),
|
|
68
|
+
model: modelName,
|
|
69
|
+
choices: [
|
|
70
|
+
{
|
|
71
|
+
index: 0,
|
|
72
|
+
message: {
|
|
73
|
+
role: 'assistant',
|
|
74
|
+
content: LangChainAdapter.extractTextContent(response.content),
|
|
75
|
+
refusal: null,
|
|
76
|
+
tool_calls: toolCalls?.length ? toolCalls : undefined,
|
|
77
|
+
},
|
|
78
|
+
finish_reason: toolCalls?.length ? 'tool_calls' : 'stop',
|
|
79
|
+
logprobs: null,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
usage: {
|
|
83
|
+
prompt_tokens: usageMetadata?.input_tokens ?? 0,
|
|
84
|
+
completion_tokens: usageMetadata?.output_tokens ?? 0,
|
|
85
|
+
total_tokens: usageMetadata?.total_tokens ?? 0,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** Convert OpenAI tool_choice to LangChain format. */
|
|
90
|
+
static convertToolChoice(toolChoice) {
|
|
91
|
+
if (!toolChoice)
|
|
92
|
+
return undefined;
|
|
93
|
+
if (toolChoice === 'auto')
|
|
94
|
+
return 'auto';
|
|
95
|
+
if (toolChoice === 'none')
|
|
96
|
+
return 'none';
|
|
97
|
+
if (toolChoice === 'required')
|
|
98
|
+
return 'any';
|
|
99
|
+
if (typeof toolChoice === 'object' && toolChoice.type === 'function') {
|
|
100
|
+
return { type: 'tool', name: toolChoice.function.name };
|
|
101
|
+
}
|
|
102
|
+
throw new errors_1.AIBadRequestError(`Unsupported tool_choice value. Expected: 'auto', 'none', 'required', or {type: 'function', function: {name: '...'}}.`);
|
|
103
|
+
}
|
|
104
|
+
static extractTextContent(content) {
|
|
105
|
+
if (typeof content === 'string')
|
|
106
|
+
return content || null;
|
|
107
|
+
if (Array.isArray(content)) {
|
|
108
|
+
const text = content
|
|
109
|
+
.filter(block => block.type === 'text')
|
|
110
|
+
.map(block => ('text' in block ? block.text : ''))
|
|
111
|
+
.join('');
|
|
112
|
+
return text || null;
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
static parseToolArguments(toolName, args) {
|
|
117
|
+
try {
|
|
118
|
+
return JSON.parse(args);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
throw new errors_1.AIBadRequestError(`Invalid JSON in tool_calls arguments for tool '${toolName}': ${args}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.LangChainAdapter = LangChainAdapter;
|
|
126
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGFuZ2NoYWluLWFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbGFuZ2NoYWluLWFkYXB0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBR0EsdURBQStGO0FBQy9GLG9EQUE0QjtBQUU1QixxQ0FBNkM7QUEyQzdDLHVFQUF1RTtBQUN2RSxNQUFhLGdCQUFnQjtJQUMzQiw0REFBNEQ7SUFDNUQsTUFBTSxDQUFDLGVBQWUsQ0FBQyxRQUF5QjtRQUM5QyxNQUFNLE1BQU0sR0FBa0IsRUFBRSxDQUFDO1FBRWpDLEtBQUssTUFBTSxHQUFHLElBQUksUUFBUSxFQUFFLENBQUM7WUFDM0IsUUFBUSxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ2pCLEtBQUssUUFBUTtvQkFDWCxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksd0JBQWEsQ0FBQyxHQUFHLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7b0JBQ2xELE1BQU07Z0JBQ1IsS0FBSyxNQUFNO29CQUNULE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSx1QkFBWSxDQUFDLEdBQUcsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztvQkFDakQsTUFBTTtnQkFDUixLQUFLLFdBQVc7b0JBQ2QsSUFBSSxHQUFHLENBQUMsVUFBVSxFQUFFLENBQUM7d0JBQ25CLE1BQU0sQ0FBQyxJQUFJLENBQ1QsSUFBSSxvQkFBUyxDQUFDOzRCQUNaLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTyxJQUFJLEVBQUU7NEJBQzFCLFVBQVUsRUFBRSxHQUFHLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7Z0NBQ3BDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRTtnQ0FDVCxJQUFJLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJO2dDQUN0QixJQUFJLEVBQUUsZ0JBQWdCLENBQUMsa0JBQWtCLENBQ3ZDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUNoQixFQUFFLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FDdEI7NkJBQ0YsQ0FBQyxDQUFDO3lCQUNKLENBQUMsQ0FDSCxDQUFDO29CQUNKLENBQUM7eUJBQU0sQ0FBQzt3QkFDTixNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksb0JBQVMsQ0FBQyxHQUFHLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7b0JBQ2hELENBQUM7b0JBRUQsTUFBTTtnQkFDUixLQUFLLE1BQU07b0JBQ1QsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsQ0FBQzt3QkFDdEIsTUFBTSxJQUFJLDBCQUFpQixDQUFDLHdEQUF3RCxDQUFDLENBQUM7b0JBQ3hGLENBQUM7b0JBRUQsTUFBTSxDQUFDLElBQUksQ0FDVCxJQUFJLHNCQUFXLENBQUM7d0JBQ2QsT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPLElBQUksRUFBRTt3QkFDMUIsWUFBWSxFQUFFLEdBQUcsQ0FBQyxZQUFZO3FCQUMvQixDQUFDLENBQ0gsQ0FBQztvQkFDRixNQUFNO2dCQUNSO29CQUNFLE1BQU0sSUFBSSwwQkFBaUIsQ0FDekIsNkJBQ0csR0FBd0IsQ0FBQyxJQUM1QixnREFBZ0QsQ0FDakQsQ0FBQztZQUNOLENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELG9GQUFvRjtJQUNwRixNQUFNLENBQUMsZUFBZSxDQUFDLFFBQW1CLEVBQUUsU0FBd0I7UUFDbEUsTUFBTSxTQUFTLEdBQUcsUUFBUSxDQUFDLFVBQVUsRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ2hELEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxJQUFJLFFBQVEsZ0JBQU0sQ0FBQyxVQUFVLEVBQUUsRUFBRTtZQUMxQyxJQUFJLEVBQUUsVUFBbUI7WUFDekIsUUFBUSxFQUFFO2dCQUNSLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSTtnQkFDYixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDO2FBQ25DO1NBQ0YsQ0FBQyxDQUFDLENBQUM7UUFFSixNQUFNLGFBQWEsR0FBRyxRQUFRLENBQUMsY0FFbEIsQ0FBQztRQUVkLE9BQU87WUFDTCxFQUFFLEVBQUUsUUFBUSxDQUFDLEVBQUUsSUFBSSxPQUFPLGdCQUFNLENBQUMsVUFBVSxFQUFFLEVBQUU7WUFDL0MsTUFBTSxFQUFFLGlCQUFpQjtZQUN6QixPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO1lBQ3RDLEtBQUssRUFBRSxTQUFTO1lBQ2hCLE9BQU8sRUFBRTtnQkFDUDtvQkFDRSxLQUFLLEVBQUUsQ0FBQztvQkFDUixPQUFPLEVBQUU7d0JBQ1AsSUFBSSxFQUFFLFdBQVc7d0JBQ2pCLE9BQU8sRUFBRSxnQkFBZ0IsQ0FBQyxrQkFBa0IsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO3dCQUM5RCxPQUFPLEVBQUUsSUFBSTt3QkFDYixVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxTQUFTO3FCQUN0RDtvQkFDRCxhQUFhLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxNQUFNO29CQUN4RCxRQUFRLEVBQUUsSUFBSTtpQkFDZjthQUNGO1lBQ0QsS0FBSyxFQUFFO2dCQUNMLGFBQWEsRUFBRSxhQUFhLEVBQUUsWUFBWSxJQUFJLENBQUM7Z0JBQy9DLGlCQUFpQixFQUFFLGFBQWEsRUFBRSxhQUFhLElBQUksQ0FBQztnQkFDcEQsWUFBWSxFQUFFLGFBQWEsRUFBRSxZQUFZLElBQUksQ0FBQzthQUMvQztTQUNGLENBQUM7SUFDSixDQUFDO0lBRUQsc0RBQXNEO0lBQ3RELE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxVQUFnRDtRQUN2RSxJQUFJLENBQUMsVUFBVTtZQUFFLE9BQU8sU0FBUyxDQUFDO1FBQ2xDLElBQUksVUFBVSxLQUFLLE1BQU07WUFBRSxPQUFPLE1BQU0sQ0FBQztRQUN6QyxJQUFJLFVBQVUsS0FBSyxNQUFNO1lBQUUsT0FBTyxNQUFNLENBQUM7UUFDekMsSUFBSSxVQUFVLEtBQUssVUFBVTtZQUFFLE9BQU8sS0FBSyxDQUFDO1FBRTVDLElBQUksT0FBTyxVQUFVLEtBQUssUUFBUSxJQUFJLFVBQVUsQ0FBQyxJQUFJLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDckUsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLFVBQVUsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDMUQsQ0FBQztRQUVELE1BQU0sSUFBSSwwQkFBaUIsQ0FDekIsc0hBQXNILENBQ3ZILENBQUM7SUFDSixDQUFDO0lBRU8sTUFBTSxDQUFDLGtCQUFrQixDQUFDLE9BQTZCO1FBQzdELElBQUksT0FBTyxPQUFPLEtBQUssUUFBUTtZQUFFLE9BQU8sT0FBTyxJQUFJLElBQUksQ0FBQztRQUV4RCxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksR0FBRyxPQUFPO2lCQUNqQixNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLE1BQU0sQ0FBQztpQkFDdEMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztpQkFDakQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBRVosT0FBTyxJQUFJLElBQUksSUFBSSxDQUFDO1FBQ3RCLENBQUM7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFTyxNQUFNLENBQUMsa0JBQWtCLENBQUMsUUFBZ0IsRUFBRSxJQUFZO1FBQzlELElBQUksQ0FBQztZQUNILE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMxQixDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsTUFBTSxJQUFJLDBCQUFpQixDQUN6QixrREFBa0QsUUFBUSxNQUFNLElBQUksRUFBRSxDQUN2RSxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7Q0FDRjtBQTFJRCw0Q0EwSUMifQ==
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import type { AiConfiguration, ChatCompletionResponse } from './provider';
|
|
2
2
|
import type { RemoteTools } from './remote-tools';
|
|
3
3
|
import type { DispatchBody } from './schemas/route';
|
|
4
|
-
export type { AiConfiguration, AiProvider, BaseAiConfiguration, ChatCompletionMessage, ChatCompletionResponse, ChatCompletionTool, ChatCompletionToolChoice, OpenAiConfiguration, } from './provider';
|
|
4
|
+
export type { AiConfiguration, AiProvider, AnthropicConfiguration, BaseAiConfiguration, ChatCompletionMessage, ChatCompletionResponse, ChatCompletionTool, ChatCompletionToolChoice, OpenAiConfiguration, } from './provider';
|
|
5
5
|
export type { DispatchBody } from './schemas/route';
|
|
6
|
-
export
|
|
7
|
-
private readonly
|
|
6
|
+
export default class ProviderDispatcher {
|
|
7
|
+
private readonly openaiModel;
|
|
8
|
+
private readonly anthropicModel;
|
|
9
|
+
private readonly modelName;
|
|
8
10
|
private readonly remoteTools;
|
|
9
11
|
constructor(configuration: AiConfiguration | null, remoteTools: RemoteTools);
|
|
10
12
|
dispatch(body: DispatchBody): Promise<ChatCompletionResponse>;
|
|
13
|
+
private dispatchOpenAI;
|
|
14
|
+
private dispatchAnthropic;
|
|
15
|
+
/**
|
|
16
|
+
* Wraps provider errors into AI-specific error types.
|
|
17
|
+
*
|
|
18
|
+
* TODO: Currently all provider errors are wrapped as AIUnprocessableError,
|
|
19
|
+
* losing the original HTTP semantics (429 rate limit, 401 auth failure).
|
|
20
|
+
* To fix this properly we need to:
|
|
21
|
+
* 1. Add UnauthorizedError and TooManyRequestsError to datasource-toolkit
|
|
22
|
+
* 2. Add corresponding cases in the agent's error-handling middleware
|
|
23
|
+
* 3. Create AIProviderError, AIRateLimitError, AIAuthenticationError in ai-proxy
|
|
24
|
+
* with baseBusinessErrorName overrides for correct HTTP status mapping
|
|
25
|
+
*/
|
|
26
|
+
private static wrapProviderError;
|
|
11
27
|
private enrichToolDefinitions;
|
|
12
28
|
}
|
|
13
29
|
//# sourceMappingURL=provider-dispatcher.d.ts.map
|
|
@@ -1,58 +1,129 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
6
|
+
const anthropic_1 = require("@langchain/anthropic");
|
|
4
7
|
const function_calling_1 = require("@langchain/core/utils/function_calling");
|
|
5
8
|
const openai_1 = require("@langchain/openai");
|
|
9
|
+
const anthropic_adapter_1 = __importDefault(require("./anthropic-adapter"));
|
|
6
10
|
const errors_1 = require("./errors");
|
|
11
|
+
const langchain_adapter_1 = require("./langchain-adapter");
|
|
7
12
|
class ProviderDispatcher {
|
|
8
13
|
constructor(configuration, remoteTools) {
|
|
9
|
-
this.
|
|
14
|
+
this.openaiModel = null;
|
|
15
|
+
this.anthropicModel = null;
|
|
16
|
+
this.modelName = null;
|
|
10
17
|
this.remoteTools = remoteTools;
|
|
11
18
|
if (configuration?.provider === 'openai') {
|
|
12
19
|
const { provider, name, ...chatOpenAIOptions } = configuration;
|
|
13
|
-
this.
|
|
20
|
+
this.openaiModel = new openai_1.ChatOpenAI({
|
|
14
21
|
maxRetries: 0, // No retries by default - this lib is a passthrough
|
|
15
22
|
...chatOpenAIOptions,
|
|
16
23
|
__includeRawResponse: true,
|
|
17
24
|
});
|
|
18
25
|
}
|
|
26
|
+
else if (configuration?.provider === 'anthropic') {
|
|
27
|
+
const { provider, name, model, ...clientOptions } = configuration;
|
|
28
|
+
this.anthropicModel = new anthropic_1.ChatAnthropic({
|
|
29
|
+
maxRetries: 0, // No retries by default - this lib is a passthrough
|
|
30
|
+
...clientOptions,
|
|
31
|
+
model,
|
|
32
|
+
});
|
|
33
|
+
this.modelName = model;
|
|
34
|
+
}
|
|
35
|
+
else if (configuration) {
|
|
36
|
+
throw new errors_1.AIBadRequestError(`Unsupported AI provider '${configuration.provider}'.`);
|
|
37
|
+
}
|
|
19
38
|
}
|
|
20
39
|
async dispatch(body) {
|
|
21
|
-
if (
|
|
22
|
-
|
|
40
|
+
if (this.openaiModel) {
|
|
41
|
+
return this.dispatchOpenAI(body);
|
|
42
|
+
}
|
|
43
|
+
if (this.anthropicModel) {
|
|
44
|
+
return this.dispatchAnthropic(body);
|
|
23
45
|
}
|
|
46
|
+
throw new errors_1.AINotConfiguredError();
|
|
47
|
+
}
|
|
48
|
+
async dispatchOpenAI(body) {
|
|
24
49
|
const { tools, messages, tool_choice: toolChoice, parallel_tool_calls: parallelToolCalls, } = body;
|
|
25
50
|
const enrichedTools = this.enrichToolDefinitions(tools);
|
|
26
51
|
const model = enrichedTools?.length
|
|
27
|
-
? this.
|
|
52
|
+
? this.openaiModel.bindTools(enrichedTools, {
|
|
28
53
|
tool_choice: toolChoice,
|
|
29
54
|
parallel_tool_calls: parallelToolCalls,
|
|
30
55
|
})
|
|
31
|
-
: this.
|
|
56
|
+
: this.openaiModel;
|
|
57
|
+
let response;
|
|
32
58
|
try {
|
|
33
|
-
|
|
34
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
35
|
-
const rawResponse = response.additional_kwargs.__raw_response;
|
|
36
|
-
if (!rawResponse) {
|
|
37
|
-
throw new errors_1.OpenAIUnprocessableError('OpenAI response missing raw response data. This may indicate an API change.');
|
|
38
|
-
}
|
|
39
|
-
return rawResponse;
|
|
59
|
+
response = await model.invoke(messages);
|
|
40
60
|
}
|
|
41
61
|
catch (error) {
|
|
42
|
-
|
|
43
|
-
throw error;
|
|
44
|
-
const err = error;
|
|
45
|
-
if (err.status === 429) {
|
|
46
|
-
throw new errors_1.OpenAIUnprocessableError(`Rate limit exceeded: ${err.message}`);
|
|
47
|
-
}
|
|
48
|
-
if (err.status === 401) {
|
|
49
|
-
throw new errors_1.OpenAIUnprocessableError(`Authentication failed: ${err.message}`);
|
|
50
|
-
}
|
|
51
|
-
throw new errors_1.OpenAIUnprocessableError(`Error while calling OpenAI: ${err.message}`);
|
|
62
|
+
throw ProviderDispatcher.wrapProviderError(error, 'OpenAI');
|
|
52
63
|
}
|
|
64
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
65
|
+
const rawResponse = response.additional_kwargs.__raw_response;
|
|
66
|
+
if (!rawResponse) {
|
|
67
|
+
throw new errors_1.AIUnprocessableError('OpenAI response missing raw response data. This may indicate an API change.');
|
|
68
|
+
}
|
|
69
|
+
return rawResponse;
|
|
70
|
+
}
|
|
71
|
+
async dispatchAnthropic(body) {
|
|
72
|
+
const { tools, messages, tool_choice: toolChoice, parallel_tool_calls: parallelToolCalls, } = body;
|
|
73
|
+
// Convert messages outside try-catch so input validation errors propagate directly
|
|
74
|
+
const langChainMessages = anthropic_adapter_1.default.convertMessages(messages);
|
|
75
|
+
const enrichedTools = this.enrichToolDefinitions(tools);
|
|
76
|
+
const model = enrichedTools?.length
|
|
77
|
+
? anthropic_adapter_1.default.bindTools(this.anthropicModel, enrichedTools, {
|
|
78
|
+
toolChoice,
|
|
79
|
+
parallelToolCalls,
|
|
80
|
+
})
|
|
81
|
+
: this.anthropicModel;
|
|
82
|
+
let response;
|
|
83
|
+
try {
|
|
84
|
+
response = (await model.invoke(langChainMessages));
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
throw ProviderDispatcher.wrapProviderError(error, 'Anthropic');
|
|
88
|
+
}
|
|
89
|
+
return langchain_adapter_1.LangChainAdapter.convertResponse(response, this.modelName);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Wraps provider errors into AI-specific error types.
|
|
93
|
+
*
|
|
94
|
+
* TODO: Currently all provider errors are wrapped as AIUnprocessableError,
|
|
95
|
+
* losing the original HTTP semantics (429 rate limit, 401 auth failure).
|
|
96
|
+
* To fix this properly we need to:
|
|
97
|
+
* 1. Add UnauthorizedError and TooManyRequestsError to datasource-toolkit
|
|
98
|
+
* 2. Add corresponding cases in the agent's error-handling middleware
|
|
99
|
+
* 3. Create AIProviderError, AIRateLimitError, AIAuthenticationError in ai-proxy
|
|
100
|
+
* with baseBusinessErrorName overrides for correct HTTP status mapping
|
|
101
|
+
*/
|
|
102
|
+
static wrapProviderError(error, providerName) {
|
|
103
|
+
if (error instanceof errors_1.AIUnprocessableError)
|
|
104
|
+
return error;
|
|
105
|
+
if (error instanceof errors_1.AIBadRequestError)
|
|
106
|
+
return error;
|
|
107
|
+
if (!(error instanceof Error)) {
|
|
108
|
+
return new errors_1.AIUnprocessableError(`Error while calling ${providerName}: ${String(error)}`);
|
|
109
|
+
}
|
|
110
|
+
const { status } = error;
|
|
111
|
+
if (status === 429) {
|
|
112
|
+
return new errors_1.AIUnprocessableError(`${providerName} rate limit exceeded: ${error.message}`, {
|
|
113
|
+
cause: error,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (status === 401) {
|
|
117
|
+
return new errors_1.AIUnprocessableError(`${providerName} authentication failed: ${error.message}`, {
|
|
118
|
+
cause: error,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return new errors_1.AIUnprocessableError(`Error while calling ${providerName}: ${error.message}`, {
|
|
122
|
+
cause: error,
|
|
123
|
+
});
|
|
53
124
|
}
|
|
54
125
|
enrichToolDefinitions(tools) {
|
|
55
|
-
if (!tools
|
|
126
|
+
if (!tools)
|
|
56
127
|
return tools;
|
|
57
128
|
const remoteToolSchemas = this.remoteTools.tools.map(remoteTool => (0, function_calling_1.convertToOpenAIFunction)(remoteTool.base));
|
|
58
129
|
return tools.map(tool => {
|
|
@@ -65,5 +136,5 @@ class ProviderDispatcher {
|
|
|
65
136
|
});
|
|
66
137
|
}
|
|
67
138
|
}
|
|
68
|
-
exports.
|
|
69
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
139
|
+
exports.default = ProviderDispatcher;
|
|
140
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlkZXItZGlzcGF0Y2hlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9wcm92aWRlci1kaXNwYXRjaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBTUEsb0RBQXFEO0FBQ3JELDZFQUFpRjtBQUNqRiw4Q0FBK0M7QUFFL0MsNEVBQW1EO0FBQ25ELHFDQUF5RjtBQUN6RiwyREFBdUQ7QUFnQnZELE1BQXFCLGtCQUFrQjtJQVNyQyxZQUFZLGFBQXFDLEVBQUUsV0FBd0I7UUFSMUQsZ0JBQVcsR0FBc0IsSUFBSSxDQUFDO1FBRXRDLG1CQUFjLEdBQXlCLElBQUksQ0FBQztRQUU1QyxjQUFTLEdBQWtCLElBQUksQ0FBQztRQUsvQyxJQUFJLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztRQUUvQixJQUFJLGFBQWEsRUFBRSxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDekMsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsR0FBRyxpQkFBaUIsRUFBRSxHQUFHLGFBQWEsQ0FBQztZQUMvRCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksbUJBQVUsQ0FBQztnQkFDaEMsVUFBVSxFQUFFLENBQUMsRUFBRSxvREFBb0Q7Z0JBQ25FLEdBQUcsaUJBQWlCO2dCQUNwQixvQkFBb0IsRUFBRSxJQUFJO2FBQzNCLENBQUMsQ0FBQztRQUNMLENBQUM7YUFBTSxJQUFJLGFBQWEsRUFBRSxRQUFRLEtBQUssV0FBVyxFQUFFLENBQUM7WUFDbkQsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEdBQUcsYUFBYSxFQUFFLEdBQUcsYUFBYSxDQUFDO1lBQ2xFLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSx5QkFBYSxDQUFDO2dCQUN0QyxVQUFVLEVBQUUsQ0FBQyxFQUFFLG9EQUFvRDtnQkFDbkUsR0FBRyxhQUFhO2dCQUNoQixLQUFLO2FBQ04sQ0FBQyxDQUFDO1lBQ0gsSUFBSSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUM7UUFDekIsQ0FBQzthQUFNLElBQUksYUFBYSxFQUFFLENBQUM7WUFDekIsTUFBTSxJQUFJLDBCQUFpQixDQUN6Qiw0QkFBNkIsYUFBc0MsQ0FBQyxRQUFRLElBQUksQ0FDakYsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFrQjtRQUMvQixJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNyQixPQUFPLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDbkMsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3hCLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3RDLENBQUM7UUFFRCxNQUFNLElBQUksNkJBQW9CLEVBQUUsQ0FBQztJQUNuQyxDQUFDO0lBRU8sS0FBSyxDQUFDLGNBQWMsQ0FBQyxJQUFrQjtRQUM3QyxNQUFNLEVBQ0osS0FBSyxFQUNMLFFBQVEsRUFDUixXQUFXLEVBQUUsVUFBVSxFQUN2QixtQkFBbUIsRUFBRSxpQkFBaUIsR0FDdkMsR0FBRyxJQUFJLENBQUM7UUFFVCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDeEQsTUFBTSxLQUFLLEdBQUcsYUFBYSxFQUFFLE1BQU07WUFDakMsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLGFBQWEsRUFBRTtnQkFDeEMsV0FBVyxFQUFFLFVBQVU7Z0JBQ3ZCLG1CQUFtQixFQUFFLGlCQUFpQjthQUN2QyxDQUFDO1lBQ0osQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUM7UUFFckIsSUFBSSxRQUFtQixDQUFDO1FBRXhCLElBQUksQ0FBQztZQUNILFFBQVEsR0FBRyxNQUFNLEtBQUssQ0FBQyxNQUFNLENBQUMsUUFBNkIsQ0FBQyxDQUFDO1FBQy9ELENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxrQkFBa0IsQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUVELGdEQUFnRDtRQUNoRCxNQUFNLFdBQVcsR0FBRyxRQUFRLENBQUMsaUJBQWlCLENBQUMsY0FBd0MsQ0FBQztRQUV4RixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDakIsTUFBTSxJQUFJLDZCQUFvQixDQUM1Qiw2RUFBNkUsQ0FDOUUsQ0FBQztRQUNKLENBQUM7UUFFRCxPQUFPLFdBQVcsQ0FBQztJQUNyQixDQUFDO0lBRU8sS0FBSyxDQUFDLGlCQUFpQixDQUFDLElBQWtCO1FBQ2hELE1BQU0sRUFDSixLQUFLLEVBQ0wsUUFBUSxFQUNSLFdBQVcsRUFBRSxVQUFVLEVBQ3ZCLG1CQUFtQixFQUFFLGlCQUFpQixHQUN2QyxHQUFHLElBQUksQ0FBQztRQUVULG1GQUFtRjtRQUNuRixNQUFNLGlCQUFpQixHQUFHLDJCQUFnQixDQUFDLGVBQWUsQ0FBQyxRQUEyQixDQUFDLENBQUM7UUFDeEYsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRXhELE1BQU0sS0FBSyxHQUFHLGFBQWEsRUFBRSxNQUFNO1lBQ2pDLENBQUMsQ0FBQywyQkFBZ0IsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxhQUFhLEVBQUU7Z0JBQzdELFVBQVU7Z0JBQ1YsaUJBQWlCO2FBQ2xCLENBQUM7WUFDSixDQUFDLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQztRQUV4QixJQUFJLFFBQW1CLENBQUM7UUFFeEIsSUFBSSxDQUFDO1lBQ0gsUUFBUSxHQUFHLENBQUMsTUFBTSxLQUFLLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQWMsQ0FBQztRQUNsRSxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sa0JBQWtCLENBQUMsaUJBQWlCLENBQUMsS0FBSyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ2pFLENBQUM7UUFFRCxPQUFPLG9DQUFnQixDQUFDLGVBQWUsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3BFLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0ssTUFBTSxDQUFDLGlCQUFpQixDQUFDLEtBQWMsRUFBRSxZQUFvQjtRQUNuRSxJQUFJLEtBQUssWUFBWSw2QkFBb0I7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUN4RCxJQUFJLEtBQUssWUFBWSwwQkFBaUI7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUVyRCxJQUFJLENBQUMsQ0FBQyxLQUFLLFlBQVksS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUM5QixPQUFPLElBQUksNkJBQW9CLENBQUMsdUJBQXVCLFlBQVksS0FBSyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzNGLENBQUM7UUFFRCxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsS0FBb0MsQ0FBQztRQUV4RCxJQUFJLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQztZQUNuQixPQUFPLElBQUksNkJBQW9CLENBQUMsR0FBRyxZQUFZLHlCQUF5QixLQUFLLENBQUMsT0FBTyxFQUFFLEVBQUU7Z0JBQ3ZGLEtBQUssRUFBRSxLQUFLO2FBQ2IsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELElBQUksTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQ25CLE9BQU8sSUFBSSw2QkFBb0IsQ0FBQyxHQUFHLFlBQVksMkJBQTJCLEtBQUssQ0FBQyxPQUFPLEVBQUUsRUFBRTtnQkFDekYsS0FBSyxFQUFFLEtBQUs7YUFDYixDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsT0FBTyxJQUFJLDZCQUFvQixDQUFDLHVCQUF1QixZQUFZLEtBQUssS0FBSyxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQ3ZGLEtBQUssRUFBRSxLQUFLO1NBQ2IsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVPLHFCQUFxQixDQUFDLEtBQTRCO1FBQ3hELElBQUksQ0FBQyxLQUFLO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFFekIsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FDaEUsSUFBQSwwQ0FBdUIsRUFBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQ3pDLENBQUM7UUFFRixPQUFPLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDdEIsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLFVBQVU7Z0JBQUUsT0FBTyxJQUFJLENBQUM7WUFFMUMsTUFBTSxZQUFZLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzFGLElBQUksWUFBWTtnQkFBRSxPQUFPLEVBQUUsR0FBRyxJQUFJLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxDQUFDO1lBRTdELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUF0S0QscUNBc0tDIn0=
|
package/dist/provider.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import type { AnthropicInput } from '@langchain/anthropic';
|
|
3
|
+
import type { ChatOpenAIFields } from '@langchain/openai';
|
|
2
4
|
import type OpenAI from 'openai';
|
|
3
5
|
export type ChatCompletionResponse = OpenAI.Chat.Completions.ChatCompletion;
|
|
4
6
|
export type ChatCompletionMessage = OpenAI.Chat.Completions.ChatCompletionMessageParam;
|
|
5
7
|
export type ChatCompletionTool = OpenAI.Chat.Completions.ChatCompletionTool;
|
|
6
8
|
export type ChatCompletionToolChoice = OpenAI.Chat.Completions.ChatCompletionToolChoiceOption;
|
|
7
|
-
export type AiProvider = 'openai';
|
|
9
|
+
export type AiProvider = 'openai' | 'anthropic';
|
|
8
10
|
/**
|
|
9
11
|
* Base configuration common to all AI providers.
|
|
10
12
|
*/
|
|
@@ -18,9 +20,18 @@ export type BaseAiConfiguration = {
|
|
|
18
20
|
* OpenAI-specific configuration.
|
|
19
21
|
* Extends base with all ChatOpenAI options (temperature, maxTokens, configuration, etc.)
|
|
20
22
|
*/
|
|
21
|
-
export type OpenAiConfiguration = BaseAiConfiguration & Omit<ChatOpenAIFields, 'model' | 'apiKey'> & {
|
|
23
|
+
export type OpenAiConfiguration = Omit<BaseAiConfiguration, 'model'> & Omit<ChatOpenAIFields, 'model' | 'apiKey'> & {
|
|
22
24
|
provider: 'openai';
|
|
23
|
-
model:
|
|
25
|
+
model: OpenAI.ChatModel | (string & NonNullable<unknown>);
|
|
24
26
|
};
|
|
25
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Anthropic-specific configuration.
|
|
29
|
+
* Extends base with all ChatAnthropic options (temperature, maxTokens, etc.)
|
|
30
|
+
* Supports both `apiKey` (unified) and `anthropicApiKey` (native) for flexibility.
|
|
31
|
+
*/
|
|
32
|
+
export type AnthropicConfiguration = Omit<BaseAiConfiguration, 'model'> & Omit<AnthropicInput, 'model' | 'apiKey'> & {
|
|
33
|
+
provider: 'anthropic';
|
|
34
|
+
model: Anthropic.Messages.Model;
|
|
35
|
+
};
|
|
36
|
+
export type AiConfiguration = OpenAiConfiguration | AnthropicConfiguration;
|
|
26
37
|
//# sourceMappingURL=provider.d.ts.map
|
package/dist/router.js
CHANGED
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.Router = void 0;
|
|
7
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
|
+
const provider_dispatcher_1 = __importDefault(require("./provider-dispatcher"));
|
|
10
10
|
const remote_tools_1 = require("./remote-tools");
|
|
11
11
|
const route_1 = require("./schemas/route");
|
|
12
12
|
const supported_models_1 = __importDefault(require("./supported-models"));
|
|
@@ -19,7 +19,7 @@ class Router {
|
|
|
19
19
|
}
|
|
20
20
|
validateConfigurations() {
|
|
21
21
|
for (const config of this.aiConfigurations) {
|
|
22
|
-
if (!(0, supported_models_1.default)(config.model)) {
|
|
22
|
+
if (!(0, supported_models_1.default)(config.model, config.provider)) {
|
|
23
23
|
throw new errors_1.AIModelNotSupportedError(config.model);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -48,7 +48,7 @@ class Router {
|
|
|
48
48
|
switch (validatedArgs.route) {
|
|
49
49
|
case 'ai-query': {
|
|
50
50
|
const aiConfiguration = this.getAiConfiguration(validatedArgs.query?.['ai-name']);
|
|
51
|
-
return await new provider_dispatcher_1.
|
|
51
|
+
return await new provider_dispatcher_1.default(aiConfiguration, remoteTools).dispatch(validatedArgs.body);
|
|
52
52
|
}
|
|
53
53
|
case 'invoke-remote-tool':
|
|
54
54
|
return await remoteTools.invokeTool(validatedArgs.query['tool-name'], validatedArgs.body.inputs);
|
|
@@ -100,7 +100,7 @@ class Router {
|
|
|
100
100
|
const config = this.aiConfigurations.find(c => c.name === aiName);
|
|
101
101
|
if (!config) {
|
|
102
102
|
const fallback = this.aiConfigurations[0];
|
|
103
|
-
this.logger?.('Warn', `AI configuration '${aiName}' not found. Falling back to '${fallback.name}'
|
|
103
|
+
this.logger?.('Warn', `AI configuration '${aiName}' not found. Falling back to '${fallback.name}' (provider: ${fallback.provider}, model: ${fallback.model})`);
|
|
104
104
|
return fallback;
|
|
105
105
|
}
|
|
106
106
|
return config;
|
|
@@ -109,4 +109,4 @@ class Router {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
exports.Router = Router;
|
|
112
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
112
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFPQSxxQ0FBdUU7QUFDdkUsOERBQXFDO0FBQ3JDLGdGQUF1RDtBQUN2RCxpREFBNkM7QUFDN0MsMkNBQWtEO0FBQ2xELDBFQUF3RDtBQWdCeEQsTUFBYSxNQUFNO0lBS2pCLFlBQVksTUFJWDtRQUNDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxNQUFNLEVBQUUsZ0JBQWdCLElBQUksRUFBRSxDQUFDO1FBQ3ZELElBQUksQ0FBQyxpQkFBaUIsR0FBRyxNQUFNLEVBQUUsaUJBQWlCLENBQUM7UUFDbkQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLEVBQUUsTUFBTSxDQUFDO1FBRTdCLElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO0lBQ2hDLENBQUM7SUFFTyxzQkFBc0I7UUFDNUIsS0FBSyxNQUFNLE1BQU0sSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUMzQyxJQUFJLENBQUMsSUFBQSwwQkFBc0IsRUFBQyxNQUFNLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUMzRCxNQUFNLElBQUksaUNBQXdCLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ25ELENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxLQUFLLENBQUMsS0FBSyxDQUFDLElBQW1EO1FBQzdELGlDQUFpQztRQUNqQyxNQUFNLE1BQU0sR0FBRyx1QkFBZSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUUvQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3BCLE1BQU0sSUFBSSwwQkFBaUIsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ25FLENBQUM7UUFF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
|
package/dist/schemas/route.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { McpConfiguration } from '../mcp-client';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
declare const baseQuerySchema: z.ZodObject<{
|
|
3
4
|
'ai-name': z.ZodOptional<z.ZodString>;
|
|
@@ -74,6 +75,9 @@ export type AiQueryArgs = z.infer<typeof aiQuerySchema>;
|
|
|
74
75
|
export type InvokeRemoteToolArgs = z.infer<typeof invokeRemoteToolSchema>;
|
|
75
76
|
export type RemoteToolsArgs = z.infer<typeof remoteToolsSchema>;
|
|
76
77
|
export type DispatchBody = AiQueryArgs['body'];
|
|
78
|
+
export type RouterRouteArgs = RouteArgs & {
|
|
79
|
+
mcpConfigs?: McpConfiguration;
|
|
80
|
+
};
|
|
77
81
|
export type InvokeRemoteToolBody = InvokeRemoteToolArgs['body'];
|
|
78
82
|
export type Body = DispatchBody | InvokeRemoteToolBody | undefined;
|
|
79
83
|
export type Query = z.infer<typeof baseQuerySchema>;
|
package/dist/schemas/route.js
CHANGED
|
@@ -61,4 +61,4 @@ exports.routeArgsSchema = zod_1.z.discriminatedUnion('route', [
|
|
|
61
61
|
invokeRemoteToolSchema,
|
|
62
62
|
remoteToolsSchema,
|
|
63
63
|
]);
|
|
64
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
64
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2NoZW1hcy9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFFQSw2QkFBd0I7QUFFeEIsb0RBQW9EO0FBQ3BELE1BQU0sZUFBZSxHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQUM7SUFDL0IsU0FBUyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDaEMsV0FBVyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7Q0FDbkMsQ0FBQyxDQUFDO0FBRUg7Ozs7OztHQU1HO0FBQ0gsTUFBTSxpQkFBaUIsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUNoQztJQUNFLFFBQVEsRUFBRSxPQUFDLENBQUMsS0FBSyxDQUFDLE9BQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtRQUN6QixPQUFPLEVBQUUsMkNBQTJDO0tBQ3JELENBQUM7SUFDRixLQUFLLEVBQUUsT0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUU7SUFDbEMsV0FBVyxFQUFFLE9BQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDL0IsbUJBQW1CLEVBQUUsT0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsRUFBRTtDQUM1QyxFQUNELEVBQUUsT0FBTyxFQUFFLGtDQUFrQyxFQUFFLENBQ2hELENBQUM7QUFFRixNQUFNLGFBQWEsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQzdCLEtBQUssRUFBRSxPQUFDLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQztJQUM1QixLQUFLLEVBQUUsZUFBZSxDQUFDLFFBQVEsRUFBRTtJQUNqQyxJQUFJLEVBQUUsaUJBQWlCO0NBQ3hCLENBQUMsQ0FBQztBQUVILDhEQUE4RDtBQUM5RCxNQUFNLDJCQUEyQixHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQzFDO0lBQ0UsU0FBUyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDaEMsV0FBVyxFQUFFLE9BQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxPQUFPLEVBQUUsNkNBQTZDLEVBQUUsQ0FBQztDQUNsRixFQUNELEVBQUUsT0FBTyxFQUFFLG1DQUFtQyxFQUFFLENBQ2pELENBQUM7QUFFRjs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxzQkFBc0IsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQ3RDLEtBQUssRUFBRSxPQUFDLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUFDO0lBQ3RDLEtBQUssRUFBRSwyQkFBMkI7SUFDbEMsSUFBSSxFQUFFLE9BQUMsQ0FBQyxNQUFNLENBQ1o7UUFDRSw4REFBOEQ7UUFDOUQsTUFBTSxFQUFFLE9BQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFRLEVBQUUsRUFBRSxDQUFDLEdBQUcsS0FBSyxTQUFTLElBQUksR0FBRyxLQUFLLElBQUksRUFBRTtZQUN0RSxPQUFPLEVBQUUseUNBQXlDO1NBQ25ELENBQUM7S0FDSCxFQUNELEVBQUUsT0FBTyxFQUFFLGtDQUFrQyxFQUFFLENBQ2hEO0NBQ0YsQ0FBQyxDQUFDO0FBRUgseUNBQXlDO0FBQ3pDLE1BQU0saUJBQWlCLEdBQUcsT0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNqQyxLQUFLLEVBQUUsT0FBQyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUM7SUFDaEMsS0FBSyxFQUFFLGVBQWUsQ0FBQyxRQUFRLEVBQUU7Q0FDbEMsQ0FBQyxDQUFDO0FBRUgsaUNBQWlDO0FBQ3BCLFFBQUEsZUFBZSxHQUFHLE9BQUMsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLEVBQUU7SUFDM0QsYUFBYTtJQUNiLHNCQUFzQjtJQUN0QixpQkFBaUI7Q0FDbEIsQ0FBQyxDQUFDIn0=
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Supported models must handle tool calls and the parallel_tool_calls parameter.
|
|
5
|
-
*/
|
|
6
|
-
export default function isModelSupportingTools(model: string): boolean;
|
|
1
|
+
import type { AiProvider } from './provider';
|
|
2
|
+
export default function isModelSupportingTools(model: string, provider?: AiProvider): boolean;
|
|
7
3
|
//# sourceMappingURL=supported-models.d.ts.map
|
package/dist/supported-models.js
CHANGED
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = isModelSupportingTools;
|
|
4
|
-
|
|
5
|
-
|
|
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 = [
|
|
4
|
+
// ─── OpenAI ──────────────────────────────────────────────────────────────────
|
|
5
|
+
// If a model fails the llm.integration test, add it here.
|
|
6
|
+
const OPENAI_UNSUPPORTED_PREFIXES = [
|
|
15
7
|
// Legacy models
|
|
16
8
|
'gpt-4', // Base gpt-4 doesn't honor tool_choice: required
|
|
17
9
|
'text-davinci',
|
|
@@ -37,11 +29,7 @@ const UNSUPPORTED_MODEL_PREFIXES = [
|
|
|
37
29
|
'sora', // sora-2, sora-2-pro
|
|
38
30
|
'codex', // codex-mini-latest
|
|
39
31
|
];
|
|
40
|
-
|
|
41
|
-
* OpenAI model patterns that do NOT support tool calls.
|
|
42
|
-
* Uses contains matching: model.includes(pattern)
|
|
43
|
-
*/
|
|
44
|
-
const UNSUPPORTED_MODEL_PATTERNS = [
|
|
32
|
+
const OPENAI_UNSUPPORTED_PATTERNS = [
|
|
45
33
|
// Non-chat model variants (can appear in the middle of model names)
|
|
46
34
|
'-realtime',
|
|
47
35
|
'-audio',
|
|
@@ -54,28 +42,37 @@ const UNSUPPORTED_MODEL_PATTERNS = [
|
|
|
54
42
|
'-pro',
|
|
55
43
|
'-deep-research',
|
|
56
44
|
];
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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)
|
|
45
|
+
const OPENAI_UNSUPPORTED_MODELS = [
|
|
46
|
+
'us-40-51r-vm-ev3', // Not a chat model (v1/completions only)
|
|
47
|
+
];
|
|
48
|
+
const OPENAI_SUPPORTED_OVERRIDES = ['gpt-4-turbo', 'gpt-4o', 'gpt-4.1'];
|
|
49
|
+
function isOpenAIModelSupported(model) {
|
|
50
|
+
if (OPENAI_UNSUPPORTED_MODELS.includes(model))
|
|
71
51
|
return false;
|
|
72
|
-
|
|
73
|
-
|
|
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)
|
|
52
|
+
const matchesPattern = OPENAI_UNSUPPORTED_PATTERNS.some(p => model.includes(p));
|
|
53
|
+
if (matchesPattern)
|
|
78
54
|
return false;
|
|
79
|
-
|
|
55
|
+
const matchesPrefix = OPENAI_UNSUPPORTED_PREFIXES.some(prefix => model === prefix || model.startsWith(`${prefix}-`));
|
|
56
|
+
const isOverride = OPENAI_SUPPORTED_OVERRIDES.some(override => model === override || model.startsWith(`${override}-`));
|
|
57
|
+
return !matchesPrefix || isOverride;
|
|
58
|
+
}
|
|
59
|
+
// ─── Anthropic ───────────────────────────────────────────────────────────────
|
|
60
|
+
// If a model fails the llm.integration test, add it here.
|
|
61
|
+
const ANTHROPIC_UNSUPPORTED_MODELS = [
|
|
62
|
+
'claude-3-haiku-20240307', // EOL 2025-03-14
|
|
63
|
+
'claude-3-5-haiku-20241022', // EOL 2026-02-19
|
|
64
|
+
'claude-3-5-haiku-latest', // Points to deprecated claude-3-5-haiku-20241022
|
|
65
|
+
'claude-3-7-sonnet-20250219', // EOL 2026-02-19
|
|
66
|
+
'claude-opus-4-20250514', // Requires streaming (non-streaming times out)
|
|
67
|
+
'claude-opus-4-1-20250805', // Requires streaming (non-streaming times out)
|
|
68
|
+
];
|
|
69
|
+
function isAnthropicModelSupported(model) {
|
|
70
|
+
return !ANTHROPIC_UNSUPPORTED_MODELS.includes(model);
|
|
71
|
+
}
|
|
72
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
73
|
+
function isModelSupportingTools(model, provider) {
|
|
74
|
+
if (provider === 'anthropic')
|
|
75
|
+
return isAnthropicModelSupported(model);
|
|
76
|
+
return isOpenAIModelSupported(model);
|
|
80
77
|
}
|
|
81
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
78
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VwcG9ydGVkLW1vZGVscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9zdXBwb3J0ZWQtbW9kZWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBdUZBLHlDQUlDO0FBekZELGdGQUFnRjtBQUNoRiwwREFBMEQ7QUFFMUQsTUFBTSwyQkFBMkIsR0FBRztJQUNsQyxnQkFBZ0I7SUFDaEIsT0FBTyxFQUFFLGlEQUFpRDtJQUMxRCxjQUFjO0lBQ2QsU0FBUztJQUNULE9BQU87SUFDUCxTQUFTO0lBQ1QsS0FBSztJQUNMLGdFQUFnRTtJQUNoRSxJQUFJO0lBQ0osSUFBSTtJQUNKLElBQUk7SUFDSiwwQkFBMEI7SUFDMUIsUUFBUTtJQUNSLFNBQVM7SUFDVCxLQUFLO0lBQ0wsZ0JBQWdCO0lBQ2hCLGlCQUFpQjtJQUNqQixTQUFTLEVBQUUsMENBQTBDO0lBQ3JELGNBQWMsRUFBRSx1QkFBdUI7SUFDdkMsV0FBVyxFQUFFLDZCQUE2QjtJQUMxQyxjQUFjLEVBQUUsa0NBQWtDO0lBQ2xELFdBQVcsRUFBRSxZQUFZO0lBQ3pCLE1BQU0sRUFBRSxxQkFBcUI7SUFDN0IsT0FBTyxFQUFFLG9CQUFvQjtDQUM5QixDQUFDO0FBRUYsTUFBTSwyQkFBMkIsR0FBRztJQUNsQyxvRUFBb0U7SUFDcEUsV0FBVztJQUNYLFFBQVE7SUFDUixhQUFhO0lBQ2IsTUFBTTtJQUNOLFNBQVM7SUFDVCxRQUFRO0lBQ1IsV0FBVztJQUNYLGlFQUFpRTtJQUNqRSxNQUFNO0lBQ04sZ0JBQWdCO0NBQ2pCLENBQUM7QUFFRixNQUFNLHlCQUF5QixHQUFHO0lBQ2hDLGtCQUFrQixFQUFFLHlDQUF5QztDQUM5RCxDQUFDO0FBRUYsTUFBTSwwQkFBMEIsR0FBRyxDQUFDLGFBQWEsRUFBRSxRQUFRLEVBQUUsU0FBUyxDQUFDLENBQUM7QUFFeEUsU0FBUyxzQkFBc0IsQ0FBQyxLQUFhO0lBQzNDLElBQUkseUJBQXlCLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQztRQUFFLE9BQU8sS0FBSyxDQUFDO0lBRTVELE1BQU0sY0FBYyxHQUFHLDJCQUEyQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNoRixJQUFJLGNBQWM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUVqQyxNQUFNLGFBQWEsR0FBRywyQkFBMkIsQ0FBQyxJQUFJLENBQ3BELE1BQU0sQ0FBQyxFQUFFLENBQUMsS0FBSyxLQUFLLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsTUFBTSxHQUFHLENBQUMsQ0FDN0QsQ0FBQztJQUVGLE1BQU0sVUFBVSxHQUFHLDBCQUEwQixDQUFDLElBQUksQ0FDaEQsUUFBUSxDQUFDLEVBQUUsQ0FBQyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxVQUFVLENBQUMsR0FBRyxRQUFRLEdBQUcsQ0FBQyxDQUNuRSxDQUFDO0lBRUYsT0FBTyxDQUFDLGFBQWEsSUFBSSxVQUFVLENBQUM7QUFDdEMsQ0FBQztBQUVELGdGQUFnRjtBQUNoRiwwREFBMEQ7QUFFMUQsTUFBTSw0QkFBNEIsR0FBRztJQUNuQyx5QkFBeUIsRUFBRSxpQkFBaUI7SUFDNUMsMkJBQTJCLEVBQUUsaUJBQWlCO0lBQzlDLHlCQUF5QixFQUFFLGlEQUFpRDtJQUM1RSw0QkFBNEIsRUFBRSxpQkFBaUI7SUFDL0Msd0JBQXdCLEVBQUUsK0NBQStDO0lBQ3pFLDBCQUEwQixFQUFFLCtDQUErQztDQUM1RSxDQUFDO0FBRUYsU0FBUyx5QkFBeUIsQ0FBQyxLQUFhO0lBQzlDLE9BQU8sQ0FBQyw0QkFBNEIsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDdkQsQ0FBQztBQUVELGdGQUFnRjtBQUVoRixTQUF3QixzQkFBc0IsQ0FBQyxLQUFhLEVBQUUsUUFBcUI7SUFDakYsSUFBSSxRQUFRLEtBQUssV0FBVztRQUFFLE9BQU8seUJBQXlCLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFdEUsT0FBTyxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUN2QyxDQUFDIn0=
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestadmin/ai-proxy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
"directory": "packages/ai-proxy"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
+
"@forestadmin/agent-toolkit": "1.0.0",
|
|
15
16
|
"@forestadmin/datasource-toolkit": "1.50.1",
|
|
17
|
+
"@langchain/anthropic": "1.3.17",
|
|
16
18
|
"@langchain/community": "1.1.4",
|
|
17
19
|
"@langchain/core": "1.1.15",
|
|
18
20
|
"@langchain/langgraph": "^1.1.0",
|