@auto-engineer/ai-gateway 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,339 @@
1
+ import { z } from 'zod';
2
+ import { registerTool, registerTools, startServer, isServerStarted, type ToolHandler } from '.';
3
+
4
+ // Example 1: Simple tool with basic types
5
+ interface GreetingParams extends Record<string, unknown> {
6
+ name: string;
7
+ language?: 'en' | 'es' | 'fr' | 'de';
8
+ }
9
+
10
+ registerTool<GreetingParams>(
11
+ 'greet',
12
+ {
13
+ title: 'Greeting Tool',
14
+ description: 'Greets users in different languages',
15
+ inputSchema: {
16
+ name: z.string().min(1, 'Name is required'),
17
+ language: z.enum(['en', 'es', 'fr', 'de']).optional().default('en'),
18
+ },
19
+ },
20
+ async ({ name, language = 'en' }) => {
21
+ const greetings = {
22
+ en: `Hello, ${name}!`,
23
+ es: `¡Hola, ${name}!`,
24
+ fr: `Bonjour, ${name}!`,
25
+ de: `Hallo, ${name}!`,
26
+ };
27
+
28
+ return {
29
+ content: [
30
+ {
31
+ type: 'text' as const,
32
+ text: greetings[language],
33
+ },
34
+ ],
35
+ };
36
+ },
37
+ );
38
+
39
+ // Example 2: Calculator tool with validation
40
+ interface CalculatorParams extends Record<string, unknown> {
41
+ operation: 'add' | 'subtract' | 'multiply' | 'divide';
42
+ a: number;
43
+ b: number;
44
+ }
45
+
46
+ const calculatorHandler: ToolHandler<CalculatorParams> = async ({ operation, a, b }) => {
47
+ try {
48
+ let result: number;
49
+
50
+ switch (operation) {
51
+ case 'add':
52
+ result = a + b;
53
+ break;
54
+ case 'subtract':
55
+ result = a - b;
56
+ break;
57
+ case 'multiply':
58
+ result = a * b;
59
+ break;
60
+ case 'divide':
61
+ if (b === 0) {
62
+ return {
63
+ content: [
64
+ {
65
+ type: 'text' as const,
66
+ text: 'Error: Division by zero',
67
+ },
68
+ ],
69
+ isError: true,
70
+ };
71
+ }
72
+ result = a / b;
73
+ break;
74
+ }
75
+
76
+ return {
77
+ content: [
78
+ {
79
+ type: 'text' as const,
80
+ text: `${a} ${operation} ${b} = ${result}`,
81
+ },
82
+ ],
83
+ };
84
+ } catch (error) {
85
+ return {
86
+ content: [
87
+ {
88
+ type: 'text' as const,
89
+ text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
90
+ },
91
+ ],
92
+ isError: true,
93
+ };
94
+ }
95
+ };
96
+
97
+ registerTool<CalculatorParams>(
98
+ 'calculator',
99
+ {
100
+ title: 'Calculator',
101
+ description: 'Performs basic arithmetic operations',
102
+ inputSchema: {
103
+ operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
104
+ a: z.number(),
105
+ b: z.number(),
106
+ },
107
+ },
108
+ calculatorHandler,
109
+ );
110
+
111
+ // Example 3: Batch registration of multiple tools
112
+ interface DateFormatterParams extends Record<string, unknown> {
113
+ date: string;
114
+ format: 'iso' | 'us' | 'eu';
115
+ }
116
+
117
+ interface TextAnalyzerParams extends Record<string, unknown> {
118
+ text: string;
119
+ analysis: 'wordCount' | 'charCount' | 'sentiment';
120
+ }
121
+
122
+ // Register date formatter tool
123
+ registerTool<DateFormatterParams>(
124
+ 'dateFormatter',
125
+ {
126
+ title: 'Date Formatter',
127
+ description: 'Formats dates in various styles',
128
+ inputSchema: {
129
+ date: z.string(),
130
+ format: z.enum(['iso', 'us', 'eu']),
131
+ },
132
+ },
133
+ async ({ date, format }) => {
134
+ const dateObj = new Date(date);
135
+
136
+ if (isNaN(dateObj.getTime())) {
137
+ return {
138
+ content: [
139
+ {
140
+ type: 'text' as const,
141
+ text: 'Invalid date format',
142
+ },
143
+ ],
144
+ isError: true,
145
+ };
146
+ }
147
+
148
+ const formatters = {
149
+ iso: () => dateObj.toISOString(),
150
+ us: () => dateObj.toLocaleDateString('en-US'),
151
+ eu: () => dateObj.toLocaleDateString('en-GB'),
152
+ };
153
+
154
+ return {
155
+ content: [
156
+ {
157
+ type: 'text' as const,
158
+ text: formatters[format](),
159
+ },
160
+ ],
161
+ };
162
+ },
163
+ );
164
+
165
+ // Register text analyzer tool
166
+ registerTool<TextAnalyzerParams>(
167
+ 'textAnalyzer',
168
+ {
169
+ title: 'Text Analyzer',
170
+ description: 'Analyzes text content',
171
+ inputSchema: {
172
+ text: z.string(),
173
+ analysis: z.enum(['wordCount', 'charCount', 'sentiment']),
174
+ },
175
+ },
176
+ async ({ text, analysis }) => {
177
+ const analyzers = {
178
+ wordCount: () => `Word count: ${text.split(/\s+/).filter((w) => w.length > 0).length}`,
179
+ charCount: () => `Character count: ${text.length}`,
180
+ sentiment: () => {
181
+ // Simple sentiment analysis based on keywords
182
+ const positive = ['happy', 'good', 'great', 'excellent', 'wonderful'].some((word) =>
183
+ text.toLowerCase().includes(word),
184
+ );
185
+ const negative = ['sad', 'bad', 'terrible', 'awful', 'horrible'].some((word) =>
186
+ text.toLowerCase().includes(word),
187
+ );
188
+
189
+ if (positive && !negative) return 'Sentiment: Positive 😊';
190
+ if (negative && !positive) return 'Sentiment: Negative 😢';
191
+ if (positive && negative) return 'Sentiment: Mixed 😐';
192
+ return 'Sentiment: Neutral 😐';
193
+ },
194
+ };
195
+
196
+ return {
197
+ content: [
198
+ {
199
+ type: 'text' as const,
200
+ text: analyzers[analysis](),
201
+ },
202
+ ],
203
+ };
204
+ },
205
+ );
206
+
207
+ // Example 3b: Using registerTools with same parameter types
208
+ interface MathToolParams extends Record<string, unknown> {
209
+ x: number;
210
+ y: number;
211
+ }
212
+
213
+ registerTools<MathToolParams>([
214
+ {
215
+ name: 'add',
216
+ description: {
217
+ title: 'Addition',
218
+ description: 'Adds two numbers',
219
+ inputSchema: {
220
+ x: z.number(),
221
+ y: z.number(),
222
+ },
223
+ },
224
+ handler: async ({ x, y }) => ({
225
+ content: [
226
+ {
227
+ type: 'text' as const,
228
+ text: `${x} + ${y} = ${x + y}`,
229
+ },
230
+ ],
231
+ }),
232
+ },
233
+ {
234
+ name: 'multiply',
235
+ description: {
236
+ title: 'Multiplication',
237
+ description: 'Multiplies two numbers',
238
+ inputSchema: {
239
+ x: z.number(),
240
+ y: z.number(),
241
+ },
242
+ },
243
+ handler: async ({ x, y }) => ({
244
+ content: [
245
+ {
246
+ type: 'text' as const,
247
+ text: `${x} × ${y} = ${x * y}`,
248
+ },
249
+ ],
250
+ }),
251
+ },
252
+ ]);
253
+
254
+ // Example 4: Complex tool with nested data
255
+ interface FileManagerParams extends Record<string, unknown> {
256
+ action: 'create' | 'read' | 'list';
257
+ path: string;
258
+ content?: string;
259
+ options?: {
260
+ recursive?: boolean;
261
+ encoding?: 'utf8' | 'base64';
262
+ };
263
+ }
264
+
265
+ registerTool<FileManagerParams>(
266
+ 'fileManager',
267
+ {
268
+ title: 'File Manager',
269
+ description: 'Manages files and directories',
270
+ inputSchema: {
271
+ action: z.enum(['create', 'read', 'list']),
272
+ path: z.string(),
273
+ content: z.string().optional(),
274
+ options: z
275
+ .object({
276
+ recursive: z.boolean().optional(),
277
+ encoding: z.enum(['utf8', 'base64']).optional(),
278
+ })
279
+ .optional(),
280
+ },
281
+ },
282
+ async ({ action, path, content, options }) => {
283
+ // This is a mock implementation for demonstration
284
+ const mockResponses = {
285
+ create: () => `Created file: ${path}`,
286
+ read: () => `Contents of ${path}: ${content ?? '[empty]'}`,
287
+ list: () => `Files in ${path}: file1.txt, file2.txt${options?.recursive === true ? ', subfolder/' : ''}`,
288
+ };
289
+
290
+ return {
291
+ content: [
292
+ {
293
+ type: 'text' as const,
294
+ text: mockResponses[action](),
295
+ },
296
+ ],
297
+ };
298
+ },
299
+ );
300
+
301
+ // Example usage in an application
302
+ async function main() {
303
+ // Check if server is already started
304
+ if (!isServerStarted()) {
305
+ console.log('Starting MCP server with registered tools...');
306
+
307
+ // You can register more tools here before starting
308
+ registerTool<{ message: string }>(
309
+ 'echo',
310
+ {
311
+ title: 'Echo Tool',
312
+ description: 'Echoes back the input message',
313
+ inputSchema: {
314
+ message: z.string(),
315
+ },
316
+ },
317
+ async ({ message }) => ({
318
+ content: [
319
+ {
320
+ type: 'text' as const,
321
+ text: `Echo: ${message}`,
322
+ },
323
+ ],
324
+ }),
325
+ );
326
+
327
+ // Start the server (this should only be called once in your application)
328
+ await startServer();
329
+ console.log('Server started successfully!');
330
+ } else {
331
+ console.log('Server is already running');
332
+ }
333
+ }
334
+
335
+ // Export for use in other modules
336
+ export { main };
337
+
338
+ // Demonstrate the singleton pattern
339
+ console.log('Example usage loaded. The same server instance will be used across all imports.');
@@ -0,0 +1,16 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { generateTextWithAI, streamTextWithAI, AIProvider } from './index';
3
+
4
+ describe('AI Integration', () => {
5
+ process.env.OPENAI_API_KEY = 'test';
6
+
7
+ it('should export the correct types', () => {
8
+ expect(typeof generateTextWithAI).toBe('function');
9
+ expect(typeof streamTextWithAI).toBe('function');
10
+ });
11
+
12
+ it('should have valid AIProvider type', () => {
13
+ const providers: AIProvider[] = [AIProvider.OpenAI, AIProvider.Anthropic, AIProvider.Google, AIProvider.XAI];
14
+ expect(providers).toContain(AIProvider.OpenAI);
15
+ });
16
+ });