@auto-engineer/ai-gateway 0.11.14 → 0.11.16
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +8 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +0 -2
- package/dist/src/config.js.map +1 -1
- package/dist/src/config.specs.js +1 -2
- package/dist/src/config.specs.js.map +1 -1
- package/dist/src/core/constants.d.ts +7 -0
- package/dist/src/core/constants.d.ts.map +1 -0
- package/dist/src/core/constants.js +8 -0
- package/dist/src/core/constants.js.map +1 -0
- package/dist/src/core/context.d.ts +7 -0
- package/dist/src/core/context.d.ts.map +1 -0
- package/dist/src/core/context.js +106 -0
- package/dist/src/core/context.js.map +1 -0
- package/dist/src/core/generators.d.ts +12 -0
- package/dist/src/core/generators.d.ts.map +1 -0
- package/dist/src/core/generators.js +310 -0
- package/dist/src/core/generators.js.map +1 -0
- package/dist/src/core/index.d.ts +8 -0
- package/dist/src/core/index.d.ts.map +1 -0
- package/dist/src/core/index.js +7 -0
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/core/providers/custom.d.ts +3 -0
- package/dist/src/core/providers/custom.d.ts.map +1 -0
- package/dist/src/core/providers/custom.js +9 -0
- package/dist/src/core/providers/custom.js.map +1 -0
- package/dist/src/core/types.d.ts +73 -0
- package/dist/src/core/types.d.ts.map +1 -0
- package/dist/src/core/types.js +9 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/core/utils/errors.d.ts +3 -0
- package/dist/src/core/utils/errors.d.ts.map +1 -0
- package/dist/src/core/utils/errors.js +82 -0
- package/dist/src/core/utils/errors.js.map +1 -0
- package/dist/src/core/utils/log.d.ts +3 -0
- package/dist/src/core/utils/log.d.ts.map +1 -0
- package/dist/src/core/utils/log.js +52 -0
- package/dist/src/core/utils/log.js.map +1 -0
- package/dist/src/core/utils/validation.d.ts +9 -0
- package/dist/src/core/utils/validation.d.ts.map +1 -0
- package/dist/src/core/utils/validation.js +45 -0
- package/dist/src/core/utils/validation.js.map +1 -0
- package/dist/src/index-custom.specs.js +16 -12
- package/dist/src/index-custom.specs.js.map +1 -1
- package/dist/src/index.d.ts +1 -39
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -566
- package/dist/src/index.js.map +1 -1
- package/dist/src/index.specs.js +6 -3
- package/dist/src/index.specs.js.map +1 -1
- package/dist/src/node/config.d.ts +3 -0
- package/dist/src/node/config.d.ts.map +1 -0
- package/dist/src/node/config.js +72 -0
- package/dist/src/node/config.js.map +1 -0
- package/dist/src/node/index.d.ts +11 -0
- package/dist/src/node/index.d.ts.map +1 -0
- package/dist/src/node/index.js +10 -0
- package/dist/src/node/index.js.map +1 -0
- package/dist/src/node/mcp-server.d.ts +50 -0
- package/dist/src/node/mcp-server.d.ts.map +1 -0
- package/dist/src/node/mcp-server.js +176 -0
- package/dist/src/node/mcp-server.js.map +1 -0
- package/dist/src/node/wrappers.d.ts +16 -0
- package/dist/src/node/wrappers.d.ts.map +1 -0
- package/dist/src/node/wrappers.js +100 -0
- package/dist/src/node/wrappers.js.map +1 -0
- package/dist/src/providers/custom.specs.js +1 -1
- package/dist/src/providers/custom.specs.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +19 -3
- package/src/config.specs.ts +1 -2
- package/src/config.ts +0 -2
- package/src/core/constants.ts +8 -0
- package/src/core/context.ts +106 -0
- package/src/core/generators.ts +424 -0
- package/src/core/index.ts +29 -0
- package/src/core/providers/custom.ts +10 -0
- package/src/core/types.ts +81 -0
- package/src/core/utils/errors.ts +91 -0
- package/src/core/utils/log.ts +65 -0
- package/src/core/utils/validation.ts +69 -0
- package/src/index-custom.specs.ts +16 -12
- package/src/index.specs.ts +7 -4
- package/src/index.ts +1 -756
- package/src/node/config.ts +100 -0
- package/src/node/index.ts +60 -0
- package/src/node/mcp-server.ts +261 -0
- package/src/node/wrappers.ts +136 -0
- package/src/providers/custom.specs.ts +2 -2
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { dirname, resolve } from 'path';
|
|
4
|
+
import createDebug from 'debug';
|
|
5
|
+
import { CustomProviderConfig, AIConfig } from '../core/types';
|
|
6
|
+
|
|
7
|
+
const debug = createDebug('auto:ai-gateway:config');
|
|
8
|
+
const debugEnv = createDebug('auto:ai-gateway:config:env');
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
|
|
13
|
+
const envPath = resolve(__dirname, '../../../../.env');
|
|
14
|
+
debug('Loading environment from: %s', envPath);
|
|
15
|
+
dotenv.config({ path: envPath });
|
|
16
|
+
|
|
17
|
+
function logProviderConfig(providerName: string, apiKey: string | undefined): void {
|
|
18
|
+
if (apiKey !== undefined) {
|
|
19
|
+
debug('%s provider configured with API key ending in: ...%s', providerName, apiKey.slice(-4));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function buildCustomProviderConfig(): CustomProviderConfig | undefined {
|
|
24
|
+
const name = process.env.CUSTOM_PROVIDER_NAME;
|
|
25
|
+
const baseUrl = process.env.CUSTOM_PROVIDER_BASE_URL;
|
|
26
|
+
const apiKey = process.env.CUSTOM_PROVIDER_API_KEY;
|
|
27
|
+
const defaultModel = process.env.CUSTOM_PROVIDER_DEFAULT_MODEL;
|
|
28
|
+
|
|
29
|
+
if (
|
|
30
|
+
name != null &&
|
|
31
|
+
name.length > 0 &&
|
|
32
|
+
baseUrl != null &&
|
|
33
|
+
baseUrl.length > 0 &&
|
|
34
|
+
apiKey != null &&
|
|
35
|
+
apiKey.length > 0 &&
|
|
36
|
+
defaultModel != null &&
|
|
37
|
+
defaultModel.length > 0
|
|
38
|
+
) {
|
|
39
|
+
return {
|
|
40
|
+
name,
|
|
41
|
+
baseUrl,
|
|
42
|
+
apiKey,
|
|
43
|
+
defaultModel,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function buildProviderConfig(): AIConfig {
|
|
51
|
+
return {
|
|
52
|
+
openai: process.env.OPENAI_API_KEY != null ? { apiKey: process.env.OPENAI_API_KEY } : undefined,
|
|
53
|
+
anthropic: process.env.ANTHROPIC_API_KEY != null ? { apiKey: process.env.ANTHROPIC_API_KEY } : undefined,
|
|
54
|
+
google: process.env.GEMINI_API_KEY != null ? { apiKey: process.env.GEMINI_API_KEY } : undefined,
|
|
55
|
+
xai: process.env.XAI_API_KEY != null ? { apiKey: process.env.XAI_API_KEY } : undefined,
|
|
56
|
+
custom: buildCustomProviderConfig(),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function configureAIProvider(): AIConfig {
|
|
61
|
+
debugEnv('Checking environment variables for AI providers');
|
|
62
|
+
|
|
63
|
+
const config = buildProviderConfig();
|
|
64
|
+
|
|
65
|
+
debugEnv('OpenAI configured: %s', config.openai != null);
|
|
66
|
+
debugEnv('Anthropic configured: %s', config.anthropic != null);
|
|
67
|
+
debugEnv('Google configured: %s', config.google != null);
|
|
68
|
+
debugEnv('XAI configured: %s', config.xai != null);
|
|
69
|
+
debugEnv('Custom configured: %s', config.custom != null);
|
|
70
|
+
|
|
71
|
+
logProviderConfig('OpenAI', config.openai?.apiKey);
|
|
72
|
+
logProviderConfig('Anthropic', config.anthropic?.apiKey);
|
|
73
|
+
logProviderConfig('Google', config.google?.apiKey);
|
|
74
|
+
logProviderConfig('XAI', config.xai?.apiKey);
|
|
75
|
+
|
|
76
|
+
if (config.custom != null) {
|
|
77
|
+
debug(
|
|
78
|
+
'Custom provider configured: %s at %s with model %s',
|
|
79
|
+
config.custom.name,
|
|
80
|
+
config.custom.baseUrl,
|
|
81
|
+
config.custom.defaultModel,
|
|
82
|
+
);
|
|
83
|
+
logProviderConfig('Custom', config.custom.apiKey);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const configuredProviders = [config.openai, config.anthropic, config.google, config.xai, config.custom].filter(
|
|
87
|
+
(p) => p != null,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (configuredProviders.length === 0) {
|
|
91
|
+
debug('ERROR: No AI providers configured');
|
|
92
|
+
throw new Error(
|
|
93
|
+
'At least one AI provider must be configured. Please set OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, XAI_API_KEY environment variables, or configure a custom provider with CUSTOM_PROVIDER_NAME, CUSTOM_PROVIDER_BASE_URL, CUSTOM_PROVIDER_API_KEY, and CUSTOM_PROVIDER_DEFAULT_MODEL.',
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
debug('AI configuration complete - %d provider(s) available', configuredProviders.length);
|
|
98
|
+
|
|
99
|
+
return config;
|
|
100
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export { AIProvider } from '../core/types';
|
|
2
|
+
export type {
|
|
3
|
+
CustomProviderConfig,
|
|
4
|
+
AIConfig,
|
|
5
|
+
AIContext,
|
|
6
|
+
AIOptions,
|
|
7
|
+
StructuredAIOptions,
|
|
8
|
+
StreamStructuredAIOptions,
|
|
9
|
+
AIToolValidationError,
|
|
10
|
+
RegisteredToolForAI,
|
|
11
|
+
} from '../core/types';
|
|
12
|
+
|
|
13
|
+
export { DEFAULT_MODELS } from '../core/constants';
|
|
14
|
+
|
|
15
|
+
export { createAIContext, getModel } from '../core/context';
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
generateText,
|
|
19
|
+
streamText,
|
|
20
|
+
generateTextStreaming,
|
|
21
|
+
generateTextWithImage,
|
|
22
|
+
generateStructuredData,
|
|
23
|
+
streamStructuredData,
|
|
24
|
+
generateTextWithTools,
|
|
25
|
+
} from '../core/generators';
|
|
26
|
+
|
|
27
|
+
export { createCustomProvider } from '../core/providers/custom';
|
|
28
|
+
|
|
29
|
+
export { configureAIProvider } from './config';
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
getDefaultAIProvider,
|
|
33
|
+
getDefaultModel,
|
|
34
|
+
getAvailableProviders,
|
|
35
|
+
generateTextWithAI,
|
|
36
|
+
streamTextWithAI,
|
|
37
|
+
generateTextStreamingWithAI,
|
|
38
|
+
generateTextWithImageAI,
|
|
39
|
+
generateStructuredDataWithAI,
|
|
40
|
+
streamStructuredDataWithAI,
|
|
41
|
+
generateTextWithToolsAI,
|
|
42
|
+
resetGlobalContext,
|
|
43
|
+
} from './wrappers';
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
server as mcpServer,
|
|
47
|
+
registerTool,
|
|
48
|
+
registerTools,
|
|
49
|
+
startServer,
|
|
50
|
+
isServerStarted,
|
|
51
|
+
getRegisteredTools,
|
|
52
|
+
getRegisteredToolsForAI,
|
|
53
|
+
getToolHandler,
|
|
54
|
+
getSchemaByName,
|
|
55
|
+
executeRegisteredTool,
|
|
56
|
+
type ToolHandler,
|
|
57
|
+
type RegisteredTool,
|
|
58
|
+
} from './mcp-server';
|
|
59
|
+
|
|
60
|
+
export { z } from 'zod';
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import createDebug from 'debug';
|
|
5
|
+
|
|
6
|
+
const debug = createDebug('auto:ai-gateway:mcp');
|
|
7
|
+
const debugServer = createDebug('auto:ai-gateway:mcp:server');
|
|
8
|
+
const debugTools = createDebug('auto:ai-gateway:mcp:tools');
|
|
9
|
+
const debugRegistry = createDebug('auto:ai-gateway:mcp:registry');
|
|
10
|
+
const debugExecution = createDebug('auto:ai-gateway:mcp:execution');
|
|
11
|
+
|
|
12
|
+
interface ToolResult {
|
|
13
|
+
content: Array<{
|
|
14
|
+
type: 'text';
|
|
15
|
+
text: string;
|
|
16
|
+
}>;
|
|
17
|
+
isError?: boolean;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface ToolDescription {
|
|
22
|
+
title: string;
|
|
23
|
+
description: string;
|
|
24
|
+
inputSchema: Record<string, z.ZodSchema>;
|
|
25
|
+
schema?: z.ZodSchema;
|
|
26
|
+
schemaName?: string;
|
|
27
|
+
schemaDescription?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type ToolHandler<T extends Record<string, unknown> = Record<string, unknown>> = (params: T) => Promise<ToolResult>;
|
|
31
|
+
|
|
32
|
+
interface RegisteredTool {
|
|
33
|
+
name: string;
|
|
34
|
+
description: ToolDescription;
|
|
35
|
+
handler: ToolHandler<Record<string, unknown>>;
|
|
36
|
+
aiSdkTool: {
|
|
37
|
+
parameters: z.ZodSchema;
|
|
38
|
+
description: string;
|
|
39
|
+
execute?: (args: Record<string, unknown>) => Promise<string>;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
debugServer('Creating MCP server instance - name: frontend-implementer, version: 0.1.0');
|
|
44
|
+
const server = new McpServer({
|
|
45
|
+
name: 'frontend-implementer',
|
|
46
|
+
version: '0.1.0',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const transport = new StdioServerTransport();
|
|
50
|
+
debugServer('StdioServerTransport created');
|
|
51
|
+
|
|
52
|
+
let isStarted = false;
|
|
53
|
+
const toolRegistry = new Map<string, RegisteredTool>();
|
|
54
|
+
debugRegistry('Tool registry initialized');
|
|
55
|
+
|
|
56
|
+
async function cleanup() {
|
|
57
|
+
debug('Cleanup initiated');
|
|
58
|
+
console.log('Cleaning up...');
|
|
59
|
+
await transport.close();
|
|
60
|
+
debugServer('Transport closed');
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
process.on('SIGTERM', () => {
|
|
65
|
+
void cleanup();
|
|
66
|
+
});
|
|
67
|
+
process.on('SIGINT', () => {
|
|
68
|
+
void cleanup();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
export { server };
|
|
72
|
+
|
|
73
|
+
function createMcpHandler<T extends Record<string, unknown>>(
|
|
74
|
+
handler: ToolHandler<T>,
|
|
75
|
+
): (args: Record<string, unknown>, extra: unknown) => Promise<ToolResult> {
|
|
76
|
+
return (args: Record<string, unknown>, _extra: unknown) => {
|
|
77
|
+
debugExecution('MCP handler invoked with args: %o', args);
|
|
78
|
+
return handler(args as T);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function createAiSdkTool(description: ToolDescription, handler: ToolHandler) {
|
|
83
|
+
const parameterSchema =
|
|
84
|
+
Object.keys(description.inputSchema).length > 0 ? z.object(description.inputSchema) : z.object({}).passthrough();
|
|
85
|
+
|
|
86
|
+
debugTools('Creating AI SDK tool with %d parameters', Object.keys(description.inputSchema).length);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
parameters: parameterSchema,
|
|
90
|
+
description: description.description,
|
|
91
|
+
execute: async (args: Record<string, unknown>) => {
|
|
92
|
+
debugExecution('AI SDK tool execute called with args: %o', args);
|
|
93
|
+
const result = await handler(args);
|
|
94
|
+
const textOutput = result.content[0]?.text || '';
|
|
95
|
+
debugExecution('Tool execution result length: %d', textOutput.length);
|
|
96
|
+
|
|
97
|
+
if (description.schema) {
|
|
98
|
+
try {
|
|
99
|
+
const parsed = JSON.parse(textOutput) as unknown;
|
|
100
|
+
description.schema.parse(parsed);
|
|
101
|
+
debugExecution('Tool output validated against schema successfully');
|
|
102
|
+
return textOutput;
|
|
103
|
+
} catch (parseError) {
|
|
104
|
+
debugExecution('Tool failed to parse/validate JSON output: %O', parseError);
|
|
105
|
+
return textOutput;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return textOutput;
|
|
110
|
+
},
|
|
111
|
+
...(description.schema && { schema: description.schema }),
|
|
112
|
+
...(description.schemaName != null && { schemaName: description.schemaName }),
|
|
113
|
+
...(description.schemaDescription != null && { schemaDescription: description.schemaDescription }),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function registerTool<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
118
|
+
name: string,
|
|
119
|
+
description: ToolDescription,
|
|
120
|
+
handler: ToolHandler<T>,
|
|
121
|
+
) {
|
|
122
|
+
debugRegistry('Registering MCP tool: %s', name);
|
|
123
|
+
console.log(`🔧 Registering MCP tool: ${name}`);
|
|
124
|
+
|
|
125
|
+
if (isStarted) {
|
|
126
|
+
debugRegistry('ERROR: Cannot register tool %s after server has started', name);
|
|
127
|
+
throw new Error('Cannot register tools after server has started');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (toolRegistry.has(name)) {
|
|
131
|
+
debugRegistry('Tool %s is already registered, skipping registration', name);
|
|
132
|
+
console.log(`Tool ${name} is already registered, skipping registration. Total tools: ${toolRegistry.size}`);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const mcpHandler = createMcpHandler(handler);
|
|
137
|
+
const aiSdkTool = createAiSdkTool(description, handler as ToolHandler<Record<string, unknown>>);
|
|
138
|
+
|
|
139
|
+
const registeredTool: RegisteredTool = {
|
|
140
|
+
name,
|
|
141
|
+
description,
|
|
142
|
+
handler: handler as ToolHandler<Record<string, unknown>>,
|
|
143
|
+
aiSdkTool,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
toolRegistry.set(name, registeredTool);
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
server.registerTool(name, description, mcpHandler);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (error instanceof Error && error.message.includes('already registered')) {
|
|
152
|
+
debugRegistry('Tool %s already registered in underlying server, ignoring error', name);
|
|
153
|
+
console.log(`⚠️ Tool ${name} already registered in underlying server, ignoring duplicate registration error`);
|
|
154
|
+
} else {
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
debugRegistry('Tool %s registered successfully. Total tools: %d', name, toolRegistry.size);
|
|
159
|
+
console.log(`✅ Tool ${name} registered successfully. Total tools: ${toolRegistry.size}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function registerTools<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
163
|
+
tools: Array<{
|
|
164
|
+
name: string;
|
|
165
|
+
description: ToolDescription;
|
|
166
|
+
handler: ToolHandler<T>;
|
|
167
|
+
}>,
|
|
168
|
+
) {
|
|
169
|
+
debugRegistry('Batch registering %d tools', tools.length);
|
|
170
|
+
if (isStarted) {
|
|
171
|
+
debugRegistry('ERROR: Cannot register tools after server has started');
|
|
172
|
+
throw new Error('Cannot register tools after server has started');
|
|
173
|
+
}
|
|
174
|
+
tools.forEach((tool) => {
|
|
175
|
+
registerTool(tool.name, tool.description, tool.handler);
|
|
176
|
+
});
|
|
177
|
+
debugRegistry('Batch registration complete');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export async function startServer() {
|
|
181
|
+
if (isStarted) {
|
|
182
|
+
debugServer('Server already started, skipping');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
debugServer('Starting MCP server...');
|
|
187
|
+
await server.connect(transport);
|
|
188
|
+
isStarted = true;
|
|
189
|
+
debugServer('MCP server started successfully');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function isServerStarted() {
|
|
193
|
+
debugServer('Checking server status: %s', isStarted ? 'started' : 'not started');
|
|
194
|
+
return isStarted;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function getRegisteredTools(): RegisteredTool[] {
|
|
198
|
+
const tools = Array.from(toolRegistry.values());
|
|
199
|
+
debugRegistry('Getting all registered tools: %d tools', tools.length);
|
|
200
|
+
return tools;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function getRegisteredToolsForAI(): Record<
|
|
204
|
+
string,
|
|
205
|
+
{
|
|
206
|
+
parameters: z.ZodSchema;
|
|
207
|
+
description: string;
|
|
208
|
+
execute?: (args: Record<string, unknown>) => Promise<string>;
|
|
209
|
+
}
|
|
210
|
+
> {
|
|
211
|
+
debugRegistry('Getting registered tools for AI. Registry size: %d', toolRegistry.size);
|
|
212
|
+
console.log(`📋 Getting registered tools for AI. Registry size: ${toolRegistry.size}`);
|
|
213
|
+
const tools: Record<
|
|
214
|
+
string,
|
|
215
|
+
{
|
|
216
|
+
parameters: z.ZodSchema;
|
|
217
|
+
description: string;
|
|
218
|
+
execute?: (args: Record<string, unknown>) => Promise<string>;
|
|
219
|
+
}
|
|
220
|
+
> = {};
|
|
221
|
+
for (const tool of toolRegistry.values()) {
|
|
222
|
+
tools[tool.name] = tool.aiSdkTool;
|
|
223
|
+
debugRegistry(' - Tool: %s', tool.name);
|
|
224
|
+
console.log(` - Tool: ${tool.name}`);
|
|
225
|
+
}
|
|
226
|
+
debugRegistry('Returning %d tools for AI', Object.keys(tools).length);
|
|
227
|
+
console.log(`📊 Returning ${Object.keys(tools).length} tools for AI`);
|
|
228
|
+
return tools;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function getToolHandler(name: string): ToolHandler | undefined {
|
|
232
|
+
const handler = toolRegistry.get(name)?.handler;
|
|
233
|
+
debugRegistry('Getting tool handler for %s: %s', name, handler ? 'found' : 'not found');
|
|
234
|
+
return handler;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export async function executeRegisteredTool(name: string, params: Record<string, unknown>): Promise<ToolResult> {
|
|
238
|
+
debugExecution('Executing registered tool: %s with params: %o', name, params);
|
|
239
|
+
const tool = toolRegistry.get(name);
|
|
240
|
+
if (!tool) {
|
|
241
|
+
debugExecution('ERROR: Tool %s not found', name);
|
|
242
|
+
throw new Error(`Tool '${name}' not found`);
|
|
243
|
+
}
|
|
244
|
+
const result = await tool.handler(params);
|
|
245
|
+
debugExecution('Tool %s executed successfully', name);
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function getSchemaByName(schemaName: string): z.ZodSchema | undefined {
|
|
250
|
+
debugRegistry('Looking for schema with name: %s', schemaName);
|
|
251
|
+
for (const tool of toolRegistry.values()) {
|
|
252
|
+
if (tool.description?.schemaName === schemaName) {
|
|
253
|
+
debugRegistry('Schema %s found in tool %s', schemaName, tool.name);
|
|
254
|
+
return tool.description.schema;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
debugRegistry('Schema %s not found', schemaName);
|
|
258
|
+
return undefined;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export type { ToolResult, ToolDescription, ToolHandler, RegisteredTool };
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { AIContext, AIOptions, StructuredAIOptions, StreamStructuredAIOptions, AIProvider } from '../core/types';
|
|
2
|
+
import {
|
|
3
|
+
createAIContext,
|
|
4
|
+
getDefaultProvider as coreGetDefaultProvider,
|
|
5
|
+
getAvailableProviders as coreGetAvailableProviders,
|
|
6
|
+
getDefaultModel as coreGetDefaultModel,
|
|
7
|
+
} from '../core/context';
|
|
8
|
+
import {
|
|
9
|
+
generateText as coreGenerateText,
|
|
10
|
+
streamText as coreStreamText,
|
|
11
|
+
generateTextStreaming as coreGenerateTextStreaming,
|
|
12
|
+
generateTextWithImage as coreGenerateTextWithImage,
|
|
13
|
+
generateStructuredData as coreGenerateStructuredData,
|
|
14
|
+
streamStructuredData as coreStreamStructuredData,
|
|
15
|
+
generateTextWithTools as coreGenerateTextWithTools,
|
|
16
|
+
} from '../core/generators';
|
|
17
|
+
import { configureAIProvider } from './config';
|
|
18
|
+
import { getRegisteredToolsForAI, startServer } from './mcp-server';
|
|
19
|
+
|
|
20
|
+
let globalContext: AIContext | null = null;
|
|
21
|
+
|
|
22
|
+
export function resetGlobalContext(): void {
|
|
23
|
+
globalContext = null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getOrCreateContext(): AIContext {
|
|
27
|
+
if (!globalContext) {
|
|
28
|
+
const config = configureAIProvider();
|
|
29
|
+
const defaultProvider = determineDefaultProvider();
|
|
30
|
+
globalContext = createAIContext(config, defaultProvider);
|
|
31
|
+
}
|
|
32
|
+
return globalContext;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function determineDefaultProvider(): AIProvider | undefined {
|
|
36
|
+
const envProvider = process.env.DEFAULT_AI_PROVIDER?.toLowerCase();
|
|
37
|
+
switch (envProvider) {
|
|
38
|
+
case 'openai':
|
|
39
|
+
return AIProvider.OpenAI;
|
|
40
|
+
case 'anthropic':
|
|
41
|
+
return AIProvider.Anthropic;
|
|
42
|
+
case 'google':
|
|
43
|
+
return AIProvider.Google;
|
|
44
|
+
case 'xai':
|
|
45
|
+
return AIProvider.XAI;
|
|
46
|
+
default:
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getDefaultAIProvider(): AIProvider {
|
|
52
|
+
const context = getOrCreateContext();
|
|
53
|
+
return coreGetDefaultProvider(context);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function getDefaultModel(provider: AIProvider): string {
|
|
57
|
+
const envModel = process.env.DEFAULT_AI_MODEL;
|
|
58
|
+
if (envModel !== undefined && envModel !== null && envModel.trim().length > 0) {
|
|
59
|
+
return envModel.trim();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const context = getOrCreateContext();
|
|
63
|
+
return coreGetDefaultModel(provider, context);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getAvailableProviders(): AIProvider[] {
|
|
67
|
+
const context = getOrCreateContext();
|
|
68
|
+
return coreGetAvailableProviders(context);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function generateTextWithAI(prompt: string, options: AIOptions = {}): Promise<string> {
|
|
72
|
+
const context = getOrCreateContext();
|
|
73
|
+
|
|
74
|
+
if (options.includeTools === true) {
|
|
75
|
+
try {
|
|
76
|
+
await startServer();
|
|
77
|
+
} catch (e) {
|
|
78
|
+
throw new Error(`MCP server failed to start: ${(e as Error).message}`);
|
|
79
|
+
}
|
|
80
|
+
const tools = getRegisteredToolsForAI();
|
|
81
|
+
const result = await coreGenerateTextWithTools(context, prompt, options, tools);
|
|
82
|
+
return result.text;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return coreGenerateText(context, prompt, options);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function* streamTextWithAI(prompt: string, options: AIOptions = {}): AsyncGenerator<string> {
|
|
89
|
+
const context = getOrCreateContext();
|
|
90
|
+
yield* coreStreamText(context, prompt, options);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function generateTextStreamingWithAI(prompt: string, options: AIOptions = {}): Promise<string> {
|
|
94
|
+
const context = getOrCreateContext();
|
|
95
|
+
return coreGenerateTextStreaming(context, prompt, options);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function generateTextWithImageAI(
|
|
99
|
+
text: string,
|
|
100
|
+
imageBase64: string,
|
|
101
|
+
options: AIOptions = {},
|
|
102
|
+
): Promise<string> {
|
|
103
|
+
const context = getOrCreateContext();
|
|
104
|
+
return coreGenerateTextWithImage(context, text, imageBase64, options);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function generateStructuredDataWithAI<T>(prompt: string, options: StructuredAIOptions<T>): Promise<T> {
|
|
108
|
+
const context = getOrCreateContext();
|
|
109
|
+
|
|
110
|
+
if (options.includeTools === true) {
|
|
111
|
+
try {
|
|
112
|
+
await startServer();
|
|
113
|
+
} catch (e) {
|
|
114
|
+
throw new Error(`MCP server failed to start: ${(e as Error).message}`);
|
|
115
|
+
}
|
|
116
|
+
const tools = getRegisteredToolsForAI();
|
|
117
|
+
return coreGenerateStructuredData(context, prompt, options, tools);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return coreGenerateStructuredData(context, prompt, options);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export async function streamStructuredDataWithAI<T>(prompt: string, options: StreamStructuredAIOptions<T>): Promise<T> {
|
|
124
|
+
const context = getOrCreateContext();
|
|
125
|
+
return coreStreamStructuredData(context, prompt, options);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export async function generateTextWithToolsAI(
|
|
129
|
+
prompt: string,
|
|
130
|
+
options: AIOptions = {},
|
|
131
|
+
): Promise<{ text: string; toolCalls?: unknown[] }> {
|
|
132
|
+
const context = getOrCreateContext();
|
|
133
|
+
await startServer();
|
|
134
|
+
const tools = getRegisteredToolsForAI();
|
|
135
|
+
return coreGenerateTextWithTools(context, prompt, options, tools);
|
|
136
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { createCustomProvider } from '
|
|
3
|
-
import { CustomProviderConfig } from '../
|
|
2
|
+
import { createCustomProvider } from '../core/providers/custom';
|
|
3
|
+
import { CustomProviderConfig } from '../core/types';
|
|
4
4
|
|
|
5
5
|
interface MockConfig {
|
|
6
6
|
name: string;
|