matimo-examples 0.1.0-alpha.11

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.
Files changed (57) hide show
  1. package/.env.example +49 -0
  2. package/LICENSE +21 -0
  3. package/README.md +525 -0
  4. package/agents/decorator-pattern-agent.ts +368 -0
  5. package/agents/factory-pattern-agent.ts +253 -0
  6. package/agents/langchain-agent.ts +146 -0
  7. package/edit/edit-decorator.ts +178 -0
  8. package/edit/edit-factory.ts +138 -0
  9. package/edit/edit-langchain.ts +292 -0
  10. package/execute/execute-decorator.ts +49 -0
  11. package/execute/execute-factory.ts +46 -0
  12. package/execute/execute-langchain.ts +232 -0
  13. package/github/github-decorator.ts +326 -0
  14. package/github/github-factory.ts +355 -0
  15. package/github/github-langchain.ts +206 -0
  16. package/github/github-with-approval.ts +228 -0
  17. package/gmail/README.md +345 -0
  18. package/gmail/gmail-decorator.ts +216 -0
  19. package/gmail/gmail-factory.ts +231 -0
  20. package/gmail/gmail-langchain.ts +201 -0
  21. package/hubspot/README.md +316 -0
  22. package/hubspot/hubspot-decorator.ts +180 -0
  23. package/hubspot/hubspot-factory.ts +188 -0
  24. package/hubspot/hubspot-langchain.ts +222 -0
  25. package/logger-example.ts +40 -0
  26. package/mailchimp/README.md +321 -0
  27. package/mailchimp/mailchimp-decorator.ts +277 -0
  28. package/mailchimp/mailchimp-factory.ts +187 -0
  29. package/mailchimp/mailchimp-langchain.ts +155 -0
  30. package/notion/README.md +293 -0
  31. package/notion/notion-decorator.ts +275 -0
  32. package/notion/notion-factory.ts +256 -0
  33. package/notion/notion-langchain.ts +237 -0
  34. package/package.json +79 -0
  35. package/postgres/README.md +188 -0
  36. package/postgres/postgres-decorator.ts +198 -0
  37. package/postgres/postgres-factory.ts +180 -0
  38. package/postgres/postgres-langchain.ts +213 -0
  39. package/postgres/postgres-with-approval.ts +344 -0
  40. package/read/read-decorator.ts +154 -0
  41. package/read/read-factory.ts +121 -0
  42. package/read/read-langchain.ts +273 -0
  43. package/search/search-decorator.ts +206 -0
  44. package/search/search-factory.ts +146 -0
  45. package/search/search-langchain.ts +255 -0
  46. package/slack/README.md +339 -0
  47. package/slack/slack-decorator.ts +245 -0
  48. package/slack/slack-factory.ts +226 -0
  49. package/slack/slack-langchain.ts +242 -0
  50. package/tsconfig.json +20 -0
  51. package/twilio/README.md +309 -0
  52. package/twilio/twilio-decorator.ts +288 -0
  53. package/twilio/twilio-factory.ts +238 -0
  54. package/twilio/twilio-langchain.ts +218 -0
  55. package/web/web-decorator.ts +52 -0
  56. package/web/web-factory.ts +70 -0
  57. package/web/web-langchain.ts +163 -0
@@ -0,0 +1,206 @@
1
+ import {
2
+ MatimoInstance,
3
+ setGlobalMatimoInstance,
4
+ tool,
5
+ getGlobalApprovalHandler,
6
+ type ApprovalRequest,
7
+ } from '@matimo/core';
8
+ import path from 'path';
9
+ import { fileURLToPath } from 'url';
10
+ import * as readline from 'readline';
11
+
12
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
+
14
+ /**
15
+ * Create an interactive approval callback
16
+ */
17
+ function createApprovalCallback() {
18
+ return async (request: ApprovalRequest): Promise<boolean> => {
19
+ const isInteractive = process.stdin.isTTY;
20
+
21
+ console.info('\n' + '='.repeat(70));
22
+ console.info('๐Ÿ”’ APPROVAL REQUIRED FOR FILE OPERATION');
23
+ console.info('='.repeat(70));
24
+ console.info(`\n๐Ÿ“‹ Tool: ${request.toolName}`);
25
+ console.info(`๐Ÿ“ Description: ${request.description || '(no description provided)'}`);
26
+ console.info(`\n๐Ÿ“„ Search Operation:`);
27
+ console.info(` Query: ${request.params.query}`);
28
+ console.info(` Directory: ${request.params.directory}`);
29
+ if (request.params.filePattern) {
30
+ console.info(` File Pattern: ${request.params.filePattern}`);
31
+ }
32
+
33
+ if (!isInteractive) {
34
+ console.info('\nโŒ REJECTED - Non-interactive environment (no terminal)');
35
+ console.info('\n๐Ÿ’ก To enable auto-approval in CI/scripts:');
36
+ console.info(' export MATIMO_AUTO_APPROVE=true');
37
+ console.info('\n๐Ÿ’ก Or approve specific patterns:');
38
+ console.info(' export MATIMO_APPROVED_PATTERNS="search"');
39
+ console.info('\n' + '='.repeat(70) + '\n');
40
+ return false;
41
+ }
42
+
43
+ // Interactive mode: prompt user
44
+ const rl = readline.createInterface({
45
+ input: process.stdin,
46
+ output: process.stdout,
47
+ });
48
+
49
+ return new Promise((resolve) => {
50
+ console.info('\nโ“ User Action Required');
51
+ const question = ' Type "yes" to approve or "no" to reject: ';
52
+
53
+ rl.question(question, (answer) => {
54
+ const approved = answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y';
55
+
56
+ if (approved) {
57
+ console.info(' โœ… Operation APPROVED by user');
58
+ } else {
59
+ console.info(' โŒ Operation REJECTED by user');
60
+ }
61
+ console.info('='.repeat(70) + '\n');
62
+
63
+ rl.close();
64
+ resolve(approved);
65
+ });
66
+ });
67
+ };
68
+ }
69
+
70
+ /**
71
+ * Example: Search tool using @tool decorator pattern
72
+ * Demonstrates class-based file search with automatic decoration
73
+ */
74
+ class FileSearcher {
75
+ @tool('search')
76
+ async findPattern(
77
+ query: string,
78
+ directory: string,
79
+ filePattern: string,
80
+ maxResults?: number
81
+ ): Promise<unknown> {
82
+ // Decorator automatically intercepts and executes via Matimo with:
83
+ // { query, directory, filePattern, maxResults }
84
+ // Positional args map to parameters in tool definition order
85
+ return undefined;
86
+ }
87
+
88
+ @tool('search')
89
+ async searchInDirectory(
90
+ query: string,
91
+ directory: string,
92
+ filePattern?: string
93
+ ): Promise<unknown> {
94
+ // Decorator automatically intercepts and executes via Matimo with:
95
+ // { query, directory, filePattern }
96
+ return undefined;
97
+ }
98
+
99
+ @tool('search')
100
+ async regexSearch(
101
+ query: string,
102
+ directory: string,
103
+ filePattern: string,
104
+ isRegex: boolean = true,
105
+ maxResults?: number
106
+ ): Promise<unknown> {
107
+ // Decorator automatically intercepts and executes via Matimo with:
108
+ // { query, directory, filePattern, isRegex, maxResults }
109
+ return undefined;
110
+ }
111
+ }
112
+
113
+ async function decoratorExample() {
114
+ // Set up decorator support with autoDiscover
115
+ const matimo = await MatimoInstance.init({ autoDiscover: true });
116
+ setGlobalMatimoInstance(matimo);
117
+
118
+ // Configure centralized approval handler
119
+ const approvalHandler = getGlobalApprovalHandler();
120
+ approvalHandler.setApprovalCallback(createApprovalCallback());
121
+
122
+ console.info('\n' + '='.repeat(70));
123
+ console.info('๐Ÿš€ Search Tool - Decorator Pattern Example');
124
+ console.info('='.repeat(70));
125
+
126
+ // Show current approval mode
127
+ const autoApproveEnabled = process.env.MATIMO_AUTO_APPROVE === 'true';
128
+ const approvedPatterns = process.env.MATIMO_APPROVED_PATTERNS;
129
+
130
+ console.info('\n๐Ÿ” APPROVAL CONFIGURATION:');
131
+ if (autoApproveEnabled) {
132
+ console.info(' โœ… MATIMO_AUTO_APPROVE=true');
133
+ console.info(' โ†’ All search operations will be AUTO-APPROVED');
134
+ } else if (approvedPatterns) {
135
+ console.info(` โœ… MATIMO_APPROVED_PATTERNS="${approvedPatterns}"`);
136
+ console.info(' โ†’ Matching operations will be auto-approved');
137
+ } else {
138
+ console.info(' โš ๏ธ INTERACTIVE MODE ENABLED');
139
+ console.info(' โ†’ You will be prompted to approve search operations');
140
+ }
141
+
142
+ // Get the workspace root (parent of examples directory)
143
+ // File is in examples/tools/search/, so go up 3 levels
144
+ const workspaceRoot = path.resolve(__dirname, '../../..');
145
+
146
+ const searcher = new FileSearcher();
147
+
148
+ try {
149
+ // Example 1: Find pattern through decorated method
150
+ console.info('\n1๏ธโƒฃ SEARCHING FOR A PATTERN');
151
+ console.info('-'.repeat(70));
152
+ console.info('Finding "export" in TypeScript files (max 5 results)\n');
153
+ const result1 = await searcher.findPattern(
154
+ 'export',
155
+ path.join(workspaceRoot, 'packages/core/src'),
156
+ '*.ts',
157
+ 5
158
+ );
159
+ if (result1) {
160
+ console.info('โœ… Total matches:', (result1 as any).totalMatches);
161
+ console.info('๐Ÿ“Š Matches found:', (result1 as any).matches?.length);
162
+ if ((result1 as any).matches?.length > 0) {
163
+ console.info('๐Ÿ“ First match:', (result1 as any).matches[0]);
164
+ }
165
+ }
166
+ console.info('---\n');
167
+
168
+ // Example 2: Search in specific directory
169
+ console.info('2๏ธโƒฃ SEARCHING IN EXAMPLES DIRECTORY');
170
+ console.info('-'.repeat(70));
171
+ console.info('Searching for "async" in TypeScript files\n');
172
+ const result2 = await searcher.searchInDirectory(
173
+ 'async',
174
+ path.join(workspaceRoot, 'examples/tools'),
175
+ '*.ts'
176
+ );
177
+ if (result2) {
178
+ console.info('โœ… Total matches:', (result2 as any).totalMatches);
179
+ console.info('๐Ÿ“Š Matches found:', (result2 as any).matches?.length);
180
+ }
181
+ console.info('---\n');
182
+
183
+ // Example 3: Regex search
184
+ console.info('3๏ธโƒฃ USING REGEX PATTERN');
185
+ console.info('-'.repeat(70));
186
+ console.info('Finding "console.info" calls (max 5 results)\n');
187
+ const result3 = await searcher.regexSearch(
188
+ 'console\\.info',
189
+ path.join(workspaceRoot, 'packages/core/src'),
190
+ '*.ts',
191
+ true,
192
+ 5
193
+ );
194
+ if (result3) {
195
+ console.info('โœ… Total matches:', (result3 as any).totalMatches);
196
+ console.info('๐Ÿ“Š Matches found:', (result3 as any).matches?.length);
197
+ }
198
+ console.info('---\n');
199
+
200
+ console.info('โœ… Decorator example completed successfully');
201
+ } catch (error: any) {
202
+ console.error('โŒ Error:', error.message);
203
+ }
204
+ }
205
+
206
+ decoratorExample();
@@ -0,0 +1,146 @@
1
+ import { MatimoInstance, getGlobalApprovalHandler, type ApprovalRequest } from '@matimo/core';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import * as readline from 'readline';
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+
8
+ /**
9
+ * Create an interactive approval callback for file operations
10
+ */
11
+ function createApprovalCallback() {
12
+ return async (request: ApprovalRequest): Promise<boolean> => {
13
+ const isInteractive = process.stdin.isTTY;
14
+
15
+ console.info('\n' + '='.repeat(70));
16
+ console.info('๐Ÿ”’ APPROVAL REQUIRED FOR FILE OPERATION');
17
+ console.info('='.repeat(70));
18
+ console.info(`\n๐Ÿ“‹ Tool: ${request.toolName}`);
19
+ console.info(`๐Ÿ“ Description: ${request.description || '(no description provided)'}`);
20
+ console.info(`\n๐Ÿ“„ File Operation:`);
21
+ console.info(` Path: ${request.params.filePath}`);
22
+ if (request.params.startLine) {
23
+ console.info(` Start Line: ${request.params.startLine}`);
24
+ }
25
+ if (request.params.endLine) {
26
+ console.info(` End Line: ${request.params.endLine}`);
27
+ }
28
+
29
+ if (!isInteractive) {
30
+ console.info('\nโŒ REJECTED - Non-interactive environment (no terminal)');
31
+ console.info('\n๐Ÿ’ก To enable auto-approval in CI/scripts:');
32
+ console.info(' export MATIMO_AUTO_APPROVE=true');
33
+ console.info('\n๐Ÿ’ก Or approve specific patterns:');
34
+ console.info(' export MATIMO_APPROVED_PATTERNS="search"');
35
+ console.info('\n' + '='.repeat(70) + '\n');
36
+ return false;
37
+ }
38
+
39
+ // Interactive mode: prompt user
40
+ const rl = readline.createInterface({
41
+ input: process.stdin,
42
+ output: process.stdout,
43
+ });
44
+
45
+ return new Promise((resolve) => {
46
+ console.info('\nโ“ User Action Required');
47
+ const question = ' Type "yes" to approve or "no" to reject: ';
48
+
49
+ rl.question(question, (answer) => {
50
+ const approved = answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y';
51
+
52
+ if (approved) {
53
+ console.info(' โœ… Operation APPROVED by user');
54
+ } else {
55
+ console.info(' โŒ Operation REJECTED by user');
56
+ }
57
+ console.info('='.repeat(70) + '\n');
58
+
59
+ rl.close();
60
+ resolve(approved);
61
+ });
62
+ });
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Example: Search tool using factory pattern
68
+ * Demonstrates searching files for patterns and content with interactive approval
69
+ */
70
+ async function searchExample() {
71
+ // Initialize Matimo with autoDiscover to find all tools (core + providers)
72
+ const matimo = await MatimoInstance.init({ autoDiscover: true });
73
+
74
+ // Configure centralized approval handler
75
+ const approvalHandler = getGlobalApprovalHandler();
76
+ approvalHandler.setApprovalCallback(createApprovalCallback());
77
+
78
+ console.info('=== Search Tool - Factory Pattern (Interactive Approval) ===\n');
79
+
80
+ // Get the workspace root (parent of examples directory)
81
+ // File is in examples/tools/search/, so go up 3 levels
82
+ const workspaceRoot = path.resolve(__dirname, '../../..');
83
+
84
+ try {
85
+ // Example 1: Search for pattern in TypeScript files
86
+ console.info('1. Searching for "import" in examples\n');
87
+ const result1 = await matimo.execute('search', {
88
+ query: 'import',
89
+ directory: path.join(workspaceRoot, 'examples/tools'),
90
+ filePattern: '*.ts',
91
+ maxResults: 5,
92
+ });
93
+
94
+ if ((result1 as any).success) {
95
+ console.info('Total matches:', (result1 as any).totalMatches);
96
+ console.info('Matches found:', (result1 as any).matches?.length);
97
+ if ((result1 as any).matches) {
98
+ (result1 as any).matches.slice(0, 3).forEach((match: any) => {
99
+ console.info(` - ${match.filePath}:${match.lineNumber}: ${match.lineContent}`);
100
+ });
101
+ }
102
+ } else {
103
+ console.info('Search denied:', (result1 as any).error);
104
+ }
105
+ console.info('---\n');
106
+
107
+ // Example 2: Search for function definitions
108
+ console.info('2. Searching for function definitions\n');
109
+ const result2 = await matimo.execute('search', {
110
+ query: 'export function',
111
+ directory: path.join(workspaceRoot, 'packages/core/src'),
112
+ filePattern: '*.ts',
113
+ maxResults: 10,
114
+ });
115
+
116
+ if ((result2 as any).success) {
117
+ console.info('Total matches:', (result2 as any).totalMatches);
118
+ console.info('Matches found:', (result2 as any).matches?.length);
119
+ } else {
120
+ console.info('Search denied:', (result2 as any).error);
121
+ }
122
+ console.info('---\n');
123
+
124
+ // Example 3: Search in specific directory with regex
125
+ console.info('3. Searching for "console.info" patterns\n');
126
+ const result3 = await matimo.execute('search', {
127
+ query: 'console\\.info',
128
+ directory: path.join(workspaceRoot, 'packages/core/src'),
129
+ filePattern: '*.ts',
130
+ isRegex: true,
131
+ maxResults: 5,
132
+ });
133
+
134
+ if ((result3 as any).success) {
135
+ console.info('Total matches:', (result3 as any).totalMatches);
136
+ console.info('Matches found:', (result3 as any).matches?.length);
137
+ } else {
138
+ console.info('Search denied:', (result3 as any).error);
139
+ }
140
+ console.info('---\n');
141
+ } catch (error: any) {
142
+ console.error('Error searching files:', error.message);
143
+ }
144
+ }
145
+
146
+ searchExample();
@@ -0,0 +1,255 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ============================================================================
4
+ * SEARCH TOOL - LANGCHAIN AI AGENT EXAMPLE
5
+ * ============================================================================
6
+ *
7
+ * PATTERN: True AI Agent with OpenAI + LangChain
8
+ * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
9
+ * This is a REAL AI agent that:
10
+ * 1. Takes natural language user requests
11
+ * 2. Uses OpenAI LLM (GPT-4o-mini) to decide when to search files
12
+ * 3. Generates appropriate search queries and patterns based on context
13
+ * 4. Executes tools autonomously
14
+ * 5. Processes results and responds naturally
15
+ *
16
+ * SETUP:
17
+ * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
18
+ * 1. Create .env file in examples/tools/:
19
+ * OPENAI_API_KEY=sk-xxxxxxxxxxxxx
20
+ *
21
+ * 2. Install dependencies:
22
+ * cd examples/tools && npm install
23
+ *
24
+ * USAGE:
25
+ * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
26
+ * # From root directory:
27
+ * pnpm search:langchain
28
+ *
29
+ * # Or from examples/tools directory:
30
+ * npm run search:langchain
31
+ *
32
+ * ============================================================================
33
+ */
34
+
35
+ import 'dotenv/config';
36
+ import * as readline from 'readline';
37
+ import { createAgent } from 'langchain';
38
+ import { ChatOpenAI } from '@langchain/openai';
39
+ import {
40
+ MatimoInstance,
41
+ convertToolsToLangChain,
42
+ type ToolDefinition,
43
+ getGlobalApprovalHandler,
44
+ type ApprovalRequest,
45
+ } from '@matimo/core';
46
+
47
+ /**
48
+ * Create an interactive approval callback for file operations
49
+ */
50
+ function createApprovalCallback() {
51
+ return async (request: ApprovalRequest): Promise<boolean> => {
52
+ const isInteractive = process.stdin.isTTY;
53
+
54
+ console.info('\n' + '='.repeat(70));
55
+ console.info('๐Ÿ”’ APPROVAL REQUIRED FOR FILE OPERATION');
56
+ console.info('='.repeat(70));
57
+ console.info(`\n๐Ÿ“‹ Tool: ${request.toolName}`);
58
+ console.info(`๐Ÿ“ Description: ${request.description || '(no description provided)'}`);
59
+ console.info(`\n๐Ÿ“„ File Operation:`);
60
+ console.info(` Path: ${request.params.filePath}`);
61
+ if (request.params.startLine) {
62
+ console.info(` Start Line: ${request.params.startLine}`);
63
+ }
64
+ if (request.params.endLine) {
65
+ console.info(` End Line: ${request.params.endLine}`);
66
+ }
67
+
68
+ if (!isInteractive) {
69
+ console.info('\nโŒ REJECTED - Non-interactive environment (no terminal)');
70
+ console.info('\n๐Ÿ’ก To enable auto-approval in CI/scripts:');
71
+ console.info(' export MATIMO_AUTO_APPROVE=true');
72
+ console.info('\n๐Ÿ’ก Or approve specific patterns:');
73
+ console.info(' export MATIMO_APPROVED_PATTERNS="search"');
74
+ console.info('\n' + '='.repeat(70) + '\n');
75
+ return false;
76
+ }
77
+
78
+ // Interactive mode: prompt user
79
+ const rl = readline.createInterface({
80
+ input: process.stdin,
81
+ output: process.stdout,
82
+ });
83
+
84
+ return new Promise((resolve) => {
85
+ console.info('\nโ“ User Action Required');
86
+ const question = ' Type "yes" to approve or "no" to reject: ';
87
+
88
+ rl.question(question, (answer) => {
89
+ const approved = answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y';
90
+
91
+ if (approved) {
92
+ console.info(' โœ… Operation APPROVED by user');
93
+ } else {
94
+ console.info(' โŒ Operation REJECTED by user');
95
+ }
96
+ console.info('='.repeat(70) + '\n');
97
+
98
+ rl.close();
99
+ resolve(approved);
100
+ });
101
+ });
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Run AI Agent with Search tool
107
+ * The agent receives natural language requests and decides what to search for
108
+ */
109
+ async function runSearchAIAgent() {
110
+ console.info('\nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—');
111
+ console.info('โ•‘ Search Tool AI Agent - LangChain + OpenAI โ•‘');
112
+ console.info('โ•‘ True autonomous agent with LLM reasoning โ•‘');
113
+ console.info('โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n');
114
+
115
+ // Check required environment variables
116
+ const openaiKey = process.env.OPENAI_API_KEY;
117
+ if (!openaiKey) {
118
+ console.error('โŒ Error: OPENAI_API_KEY not set in .env');
119
+ console.info(' Set it: export OPENAI_API_KEY="sk-..."');
120
+ process.exit(1);
121
+ }
122
+
123
+ console.info('๐Ÿค– Using OpenAI (GPT-4o-mini) as the AI agent\n');
124
+
125
+ try {
126
+ // Initialize Matimo with auto-discovery
127
+ console.info('๐Ÿš€ Initializing Matimo...');
128
+ const matimo = await MatimoInstance.init({ autoDiscover: true });
129
+
130
+ // Configure centralized approval handler
131
+ const approvalHandler = getGlobalApprovalHandler();
132
+ approvalHandler.setApprovalCallback(createApprovalCallback());
133
+
134
+ // Get search tool
135
+ console.info('๐Ÿ’ฌ Loading search tool...');
136
+ const matimoTools = matimo.listTools();
137
+ const searchTools = matimoTools.filter((t) => t.name === 'search') as ToolDefinition[];
138
+ console.info(`โœ… Loaded ${searchTools.length} search tool(s)\n`);
139
+
140
+ if (searchTools.length === 0) {
141
+ console.error('โŒ Search tool not found');
142
+ process.exit(1);
143
+ }
144
+
145
+ // Convert to LangChain tools using the built-in converter
146
+ const langchainTools = await convertToolsToLangChain(searchTools, matimo);
147
+
148
+ // Initialize OpenAI LLM
149
+ console.info('๐Ÿค– Initializing OpenAI (GPT-4o-mini) LLM...');
150
+ const model = new ChatOpenAI({
151
+ modelName: 'gpt-4o-mini',
152
+ temperature: 0.7,
153
+ });
154
+
155
+ // Create agent
156
+ console.info('๐Ÿ”ง Creating agent...\n');
157
+ const agent = await createAgent({
158
+ model,
159
+ tools: langchainTools as any,
160
+ });
161
+
162
+ // Define agent tasks (natural language requests)
163
+ const userRequests = [
164
+ {
165
+ title: 'Example 1: Search for TypeScript files',
166
+ request:
167
+ 'Search for all TypeScript files by looking for files matching the pattern "*.ts" in the packages directory',
168
+ },
169
+ {
170
+ title: 'Example 2: Search for specific imports',
171
+ request:
172
+ 'Search for all files containing "import MatimoInstance" to find where MatimoInstance is being imported',
173
+ },
174
+ {
175
+ title: 'Example 3: Search for function definitions',
176
+ request:
177
+ 'Search for files containing "export default async function" to find all exported async functions in the codebase',
178
+ },
179
+ ];
180
+
181
+ console.info('๐Ÿงช Running AI Agent Tasks');
182
+ console.info('โ•'.repeat(60) + '\n');
183
+
184
+ // Run each task through the agent
185
+ for (const task of userRequests) {
186
+ console.info(`${task.title}`);
187
+ console.info('โ”€'.repeat(60));
188
+ console.info(`๐Ÿ‘ค User: "${task.request}"\n`);
189
+
190
+ try {
191
+ // Add system context to help the LLM understand how to use the search tool
192
+ const systemPrompt = `You have access to a search tool that can find files in the filesystem.
193
+ The search tool takes a 'query' parameter which can be:
194
+ - A file pattern (glob) like '*.ts', '*.json', 'src/**/*.test.ts'
195
+ - Text to search within files like 'import MatimoInstance', 'export default function'
196
+
197
+ When the user asks you to search, extract the search query from their request and pass it to the search tool.
198
+ For example:
199
+ - If user says "find TypeScript files", use query "*.ts"
200
+ - If user says "find imports of X", use query "import X"
201
+ - If user says "find where Y is exported", use query "export Y"
202
+
203
+ Always use the search tool with the appropriate query parameter.`;
204
+
205
+ const response = await agent.invoke({
206
+ messages: [
207
+ {
208
+ role: 'system',
209
+ content: systemPrompt,
210
+ },
211
+ {
212
+ role: 'user',
213
+ content: task.request,
214
+ },
215
+ ],
216
+ });
217
+
218
+ // Get the last message from the agent
219
+ const lastMessage = response.messages[response.messages.length - 1];
220
+ if (lastMessage) {
221
+ const content =
222
+ typeof lastMessage.content === 'string'
223
+ ? lastMessage.content
224
+ : String(lastMessage.content);
225
+
226
+ if (content && content.trim()) {
227
+ console.info(`๐Ÿค– Agent: ${content}\n`);
228
+ } else {
229
+ console.info('๐Ÿค– Agent: (Search completed successfully)\n');
230
+ }
231
+ }
232
+ } catch (error) {
233
+ const errorMsg = error instanceof Error ? error.message : String(error);
234
+ console.info(`โš ๏ธ Agent error: ${errorMsg}\n`);
235
+ }
236
+ }
237
+
238
+ console.info('โ•'.repeat(60));
239
+ console.info('\nโœจ AI Agent Examples Complete!\n');
240
+ console.info('Key Features:');
241
+ console.info(' โœ… Real LLM (OpenAI) decides which tools to use');
242
+ console.info(' โœ… Natural language requests, not API calls');
243
+ console.info(' โœ… LLM generates search patterns based on context');
244
+ console.info(' โœ… Agentic reasoning and decision-making\n');
245
+ } catch (error) {
246
+ console.error('โŒ Error:', error instanceof Error ? error.message : String(error));
247
+ if (error instanceof Error && error.stack) {
248
+ console.error('Stack:', error.stack);
249
+ }
250
+ process.exit(1);
251
+ }
252
+ }
253
+
254
+ // Run the AI agent
255
+ runSearchAIAgent().catch(console.error);