matimo-examples 0.1.0-alpha.7

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,146 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Matimo + LangChain Agent - Proper ReAct Agent Pattern
4
+ *
5
+ * This demonstrates a complete agent loop:
6
+ * 1. LLM decides which tool to use based on goal
7
+ * 2. Tool is executed via Matimo
8
+ * 3. Result is fed back to LLM
9
+ * 4. Process repeats until agent reaches conclusion
10
+ *
11
+ * Key advantages:
12
+ * - Shows real agent reasoning loop
13
+ * - Single source of truth (Matimo YAML definitions)
14
+ * - How to integrate Matimo with any LangChain setup
15
+ * - Demonstrates tool selection and execution
16
+ *
17
+ * Run: npm run agent:langchain
18
+ */
19
+
20
+ import 'dotenv/config';
21
+ import path from 'path';
22
+ import { fileURLToPath } from 'url';
23
+ import { ChatOpenAI } from '@langchain/openai';
24
+ import { BaseMessage, HumanMessage, ToolMessage } from '@langchain/core/messages';
25
+ import { MatimoInstance, convertToolsToLangChain, ToolDefinition } from 'matimo';
26
+
27
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
28
+
29
+ /**
30
+ * Run LangChain ReAct Agent with Matimo Tools
31
+ */
32
+ async function runLangChainAgent() {
33
+ console.info('\n╔════════════════════════════════════════════════════════╗');
34
+ console.info('║ Matimo + LangChain Agent (ReAct Pattern) ║');
35
+ console.info('║ Demonstrates real agent reasoning loop ║');
36
+ console.info('╚════════════════════════════════════════════════════════╝\n');
37
+
38
+ try {
39
+ // Initialize Matimo
40
+ console.info('🚀 Initializing Matimo...');
41
+ const matimo = await MatimoInstance.init({ autoDiscover: true });
42
+
43
+ const matimoTools = matimo.listTools();
44
+ console.info(`📦 Loaded ${matimoTools.length} tools:\n`);
45
+ matimoTools.forEach((t) => {
46
+ console.info(` • ${t.name}`);
47
+ console.info(` ${t.description}\n`);
48
+ });
49
+
50
+ // ✅ Convert Matimo tools to LangChain tools
51
+ console.info('🔧 Converting Matimo tools to LangChain format...\n');
52
+ const langchainTools = await convertToolsToLangChain(matimoTools as ToolDefinition[], matimo);
53
+
54
+ console.info(`✅ Successfully converted ${langchainTools.length} tools!\n`);
55
+
56
+ // 🤖 Create GPT-4o-mini LLM with tool binding
57
+ console.info('🧠 Creating GPT-4o-mini LLM with tool binding...\n');
58
+ const llm = new ChatOpenAI({
59
+ model: 'gpt-4o-mini',
60
+ temperature: 0,
61
+ });
62
+
63
+ const llmWithTools = llm.bindTools(langchainTools as any);
64
+
65
+ // 🎯 Agent Loop - ReAct Pattern
66
+ console.info('🧪 Starting Agent Loop (ReAct Pattern)\n');
67
+ console.info('═'.repeat(60));
68
+
69
+ const userQuery = 'What is 42 plus 58?';
70
+ console.info(`\n❓ User Query: "${userQuery}"\n`);
71
+
72
+ const messages: BaseMessage[] = [new HumanMessage(userQuery)];
73
+
74
+ let iterationCount = 0;
75
+ const maxIterations = 10;
76
+ let continueLoop = true;
77
+
78
+ while (continueLoop && iterationCount < maxIterations) {
79
+ iterationCount++;
80
+ console.info(`\n[Iteration ${iterationCount}]`);
81
+ console.info('─'.repeat(60));
82
+
83
+ // Step 1: Call LLM with tools
84
+ console.info('🤔 LLM Thinking...');
85
+ const response = await llmWithTools.invoke(messages);
86
+ console.info(`LLM Response Content: ${response.content || '(no text content)'}`);
87
+
88
+ // Step 2: Check if LLM wants to use tools
89
+ if (response.tool_calls && response.tool_calls.length > 0) {
90
+ // Add assistant message to conversation
91
+ messages.push(response);
92
+
93
+ // Step 3: Execute each tool call
94
+ for (const toolCall of response.tool_calls) {
95
+ console.info(`\n🔧 Executing Tool: ${toolCall.name}`);
96
+ console.info(` Input: ${JSON.stringify(toolCall.args)}`);
97
+
98
+ try {
99
+ // Execute via Matimo
100
+ const result = await matimo.execute(toolCall.name, toolCall.args);
101
+ console.info(` ✅ Result: ${JSON.stringify(result)}`);
102
+
103
+ // Add tool result to conversation
104
+ messages.push(
105
+ new ToolMessage({
106
+ tool_call_id: toolCall.id || '',
107
+ content: JSON.stringify(result),
108
+ name: toolCall.name,
109
+ })
110
+ );
111
+ } catch (toolError) {
112
+ const msg = toolError instanceof Error ? toolError.message : String(toolError);
113
+ console.info(` ❌ Error: ${msg}`);
114
+
115
+ // Add error to conversation
116
+ messages.push(
117
+ new ToolMessage({
118
+ tool_call_id: toolCall.id || '',
119
+ content: `Error: ${msg}`,
120
+ name: toolCall.name,
121
+ })
122
+ );
123
+ }
124
+ }
125
+ } else {
126
+ // Step 4: No more tools - agent reached conclusion
127
+ console.info('\n✅ Agent Reached Conclusion');
128
+ console.info(`\n📝 Final Response:\n${response.content || '(no response)'}`);
129
+ continueLoop = false;
130
+ }
131
+ }
132
+
133
+ if (iterationCount >= maxIterations) {
134
+ console.info('\n⚠️ Max iterations reached');
135
+ }
136
+
137
+ console.info('\n' + '═'.repeat(60));
138
+ console.info(`\n✨ Agent Loop Complete (${iterationCount} iterations)\n`);
139
+ } catch (error) {
140
+ console.error('❌ Agent failed:', error instanceof Error ? error.message : String(error));
141
+ process.exit(1);
142
+ }
143
+ }
144
+
145
+ // Run the agent
146
+ runLangChainAgent().catch(console.error);
@@ -0,0 +1,128 @@
1
+ import {
2
+ MatimoInstance,
3
+ setGlobalMatimoInstance,
4
+ tool,
5
+ getPathApprovalManager,
6
+ } from '@matimo/core';
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ import { fileURLToPath } from 'url';
10
+ import readline from 'readline';
11
+
12
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
+
14
+ // Create readline interface for interactive approval prompts
15
+ const rl = readline.createInterface({
16
+ input: process.stdin,
17
+ output: process.stdout,
18
+ });
19
+
20
+ let isReadlineClosed = false;
21
+
22
+ // Track when readline closes (e.g., piped input ends)
23
+ rl.on('close', () => {
24
+ isReadlineClosed = true;
25
+ });
26
+
27
+ /**
28
+ * Prompt user for approval decision
29
+ */
30
+ async function promptForApproval(
31
+ filePath: string,
32
+ mode: 'read' | 'write' | 'search'
33
+ ): Promise<boolean> {
34
+ return new Promise((resolve) => {
35
+ // If readline is closed (e.g., non-TTY/piped input), auto-approve
36
+ if (isReadlineClosed) {
37
+ console.info(
38
+ `[${mode.toUpperCase()}] Access to ${filePath} auto-approved (non-interactive mode)`
39
+ );
40
+ resolve(true);
41
+ return;
42
+ }
43
+ rl.question(`[${mode.toUpperCase()}] Approve access to ${filePath}? (y/n): `, (answer) => {
44
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
45
+ });
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Example: Edit tool using @tool decorator pattern
51
+ * Demonstrates class-based file editing with automatic decoration
52
+ */
53
+ class FileEditor {
54
+ @tool('edit')
55
+ async replaceContent(
56
+ filePath: string,
57
+ operation: string,
58
+ content: string,
59
+ startLine: number,
60
+ endLine: number
61
+ ): Promise<unknown> {
62
+ // Decorator automatically intercepts and executes via Matimo
63
+ return undefined;
64
+ }
65
+
66
+ @tool('edit')
67
+ async insertContent(
68
+ filePath: string,
69
+ operation: string,
70
+ content: string,
71
+ startLine: number,
72
+ endLine: number
73
+ ): Promise<unknown> {
74
+ // Decorator automatically intercepts and executes via Matimo
75
+ return undefined;
76
+ }
77
+ }
78
+
79
+ async function decoratorExample() {
80
+ // Set up decorator support with autoDiscover
81
+ const matimo = await MatimoInstance.init({ autoDiscover: true });
82
+ setGlobalMatimoInstance(matimo);
83
+
84
+ // Set up approval callback for interactive approval
85
+ const approvalManager = getPathApprovalManager();
86
+ approvalManager.setApprovalCallback(promptForApproval);
87
+
88
+ console.info('=== Edit Tool - Decorator Pattern (Interactive Approval) ===\n');
89
+
90
+ const editor = new FileEditor();
91
+
92
+ // Create a temp file for demonstration
93
+ const tempFile = path.join(__dirname, 'temp-demo-decorator.txt');
94
+ fs.writeFileSync(tempFile, 'Original line\nAnother line\nThird line\n');
95
+
96
+ try {
97
+ // Example 1: Replace through decorated method
98
+ console.info('1. Replacing content via decorator\n');
99
+ const result1 = await editor.replaceContent(tempFile, 'replace', 'Updated line', 1, 1);
100
+ console.info('Edit Result:', (result1 as any).success);
101
+ console.info('Lines Affected:', (result1 as any).linesAffected);
102
+ console.info('File content:');
103
+ console.info(fs.readFileSync(tempFile, 'utf-8'));
104
+ console.info('---\n');
105
+
106
+ // Example 2: Insert through decorated method
107
+ console.info('2. Inserting content via decorator\n');
108
+ const result2 = await editor.insertContent(tempFile, 'insert', 'Inserted line', 1, 0);
109
+ console.info('Insert Result:', (result2 as any).success);
110
+ console.info('Lines Affected:', (result2 as any).linesAffected);
111
+ console.info('File content:');
112
+ console.info(fs.readFileSync(tempFile, 'utf-8'));
113
+ console.info('---\n');
114
+ } catch (error: any) {
115
+ console.error('Error:', error.message);
116
+ } finally {
117
+ // Clean up temp file
118
+ if (fs.existsSync(tempFile)) {
119
+ fs.unlinkSync(tempFile);
120
+ }
121
+ if (!isReadlineClosed) {
122
+ rl.close();
123
+ isReadlineClosed = true;
124
+ }
125
+ }
126
+ }
127
+
128
+ decoratorExample();
@@ -0,0 +1,120 @@
1
+ import { MatimoInstance } from '@matimo/core';
2
+ import { getPathApprovalManager } from '@matimo/core';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import readline from 'readline';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ // Reusable readline interface kept open for multiple prompts
11
+ const rl = readline.createInterface({
12
+ input: process.stdin,
13
+ output: process.stdout,
14
+ });
15
+
16
+ let isReadlineClosed = false;
17
+
18
+ // Track when readline closes (e.g., piped input ends)
19
+ rl.on('close', () => {
20
+ isReadlineClosed = true;
21
+ });
22
+
23
+ /**
24
+ * Interactive prompt helper for approval decisions
25
+ */
26
+ async function promptForApproval(
27
+ filePath: string,
28
+ mode: 'read' | 'write' | 'search'
29
+ ): Promise<boolean> {
30
+ return new Promise((resolve) => {
31
+ // If readline is closed (e.g., non-TTY/piped input), auto-approve
32
+ if (isReadlineClosed) {
33
+ console.info(
34
+ `[${mode.toUpperCase()}] Access to ${filePath} auto-approved (non-interactive mode)`
35
+ );
36
+ resolve(true);
37
+ return;
38
+ }
39
+ rl.question(`[${mode.toUpperCase()}] Approve access to ${filePath}? (y/n): `, (answer) => {
40
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
41
+ });
42
+ });
43
+ }
44
+
45
+ /**
46
+ * Example: Edit tool using factory pattern
47
+ * Demonstrates editing and modifying file contents with interactive approval
48
+ */
49
+ async function editExample() {
50
+ // Initialize Matimo with autoDiscover to find all tools (core + providers)
51
+ const matimo = await MatimoInstance.init({ autoDiscover: true });
52
+
53
+ // Set up approval callback for examples with INTERACTIVE PROMPTS
54
+ const approvalManager = getPathApprovalManager();
55
+ approvalManager.setApprovalCallback(promptForApproval);
56
+
57
+ console.info('=== Edit Tool - Factory Pattern (Interactive Approval) ===\n');
58
+
59
+ // Create a temp file for demonstration
60
+ const tempFile = path.join(__dirname, 'temp-demo.txt');
61
+ fs.writeFileSync(tempFile, 'Line 1\nLine 2\nLine 3\n');
62
+
63
+ try {
64
+ // Example 1: Replace text in file (replace line 2)
65
+ console.info('1. Replacing content in file\n');
66
+ console.info('Original content:');
67
+ console.info(fs.readFileSync(tempFile, 'utf-8'));
68
+ console.info('---\n');
69
+
70
+ const result = await matimo.execute('edit', {
71
+ filePath: tempFile,
72
+ operation: 'replace',
73
+ content: 'Line 2 (Modified)',
74
+ startLine: 2,
75
+ endLine: 2,
76
+ });
77
+
78
+ if ((result as any).success) {
79
+ console.info('Edit Result:', (result as any).success);
80
+ console.info('Lines Affected:', (result as any).linesAffected);
81
+ console.info('\nModified content:');
82
+ console.info(fs.readFileSync(tempFile, 'utf-8'));
83
+ } else {
84
+ console.info('Edit denied:', (result as any).error);
85
+ }
86
+ console.info('---\n');
87
+
88
+ // Example 2: Insert new content
89
+ console.info('2. Inserting new line\n');
90
+ const insertResult = await matimo.execute('edit', {
91
+ filePath: tempFile,
92
+ operation: 'insert',
93
+ content: 'New inserted line',
94
+ startLine: 2,
95
+ });
96
+
97
+ if ((insertResult as any).success) {
98
+ console.info('Insert Result:', (insertResult as any).success);
99
+ console.info('Lines Affected:', (insertResult as any).linesAffected);
100
+ console.info('\nFinal content:');
101
+ console.info(fs.readFileSync(tempFile, 'utf-8'));
102
+ } else {
103
+ console.info('Insert denied:', (insertResult as any).error);
104
+ }
105
+ console.info('---\n');
106
+ } catch (error: any) {
107
+ console.error('Error editing file:', error.message);
108
+ } finally {
109
+ // Clean up temp file
110
+ if (fs.existsSync(tempFile)) {
111
+ fs.unlinkSync(tempFile);
112
+ }
113
+ if (!isReadlineClosed) {
114
+ rl.close();
115
+ isReadlineClosed = true;
116
+ }
117
+ }
118
+ }
119
+
120
+ editExample();
@@ -0,0 +1,272 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ============================================================================
4
+ * EDIT 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 which edit operations to use
12
+ * 3. Generates appropriate parameters based on context
13
+ * 4. Executes tools autonomously
14
+ * 5. Processes results and responds naturally
15
+ *
16
+ * Use this pattern when:
17
+ * ✅ Building true autonomous AI agents
18
+ * ✅ LLM should decide which tools to use
19
+ * ✅ Complex workflows with LLM reasoning
20
+ * ✅ Multi-step agentic processes
21
+ * ✅ User gives high-level instructions (not low-level API calls)
22
+ *
23
+ * SETUP:
24
+ * ─────────────────────────────────────────────────────────────────────────
25
+ * 1. Create .env file in examples/tools/:
26
+ * OPENAI_API_KEY=sk-xxxxxxxxxxxxx
27
+ *
28
+ * 2. Install dependencies:
29
+ * cd examples/tools && npm install
30
+ *
31
+ * USAGE:
32
+ * ─────────────────────────────────────────────────────────────────────────
33
+ * # From root directory:
34
+ * pnpm edit:langchain
35
+ *
36
+ * # Or from examples/tools directory:
37
+ * npm run edit:langchain
38
+ *
39
+ * WHAT IT DOES:
40
+ * ─────────────────────────────────────────────────────────────────────────
41
+ * This example shows an AI agent that can:
42
+ * 1. Replace text in files
43
+ * 2. Insert new content
44
+ * 3. Delete lines
45
+ * 4. Append to files
46
+ * 5. Respond naturally in conversation style
47
+ *
48
+ * Example conversation:
49
+ * User: "Update the TODO list - mark first item as DONE and add error handling"
50
+ * AI Agent: "I'll help you update the TODO list..."
51
+ * [AI Agent calls edit tool multiple times]
52
+ * AI Agent: "Done! I've updated the file with your changes."
53
+ *
54
+ * ============================================================================
55
+ */
56
+
57
+ import 'dotenv/config';
58
+ import fs from 'fs';
59
+ import path from 'path';
60
+ import { fileURLToPath } from 'url';
61
+ import readline from 'readline';
62
+ import { createAgent } from 'langchain';
63
+ import { ChatOpenAI } from '@langchain/openai';
64
+ import {
65
+ MatimoInstance,
66
+ convertToolsToLangChain,
67
+ type ToolDefinition,
68
+ getPathApprovalManager,
69
+ } from '@matimo/core';
70
+
71
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
72
+
73
+ /**
74
+ * Run AI Agent with Edit tools
75
+ * The agent receives natural language requests and decides which edit operations to use
76
+ */
77
+ // Create readline interface for interactive approval prompts
78
+ const rl = readline.createInterface({
79
+ input: process.stdin,
80
+ output: process.stdout,
81
+ });
82
+
83
+ let isReadlineClosed = false;
84
+
85
+ // Track when readline closes (e.g., piped input ends)
86
+ rl.on('close', () => {
87
+ isReadlineClosed = true;
88
+ });
89
+
90
+ /**
91
+ * Prompt user for approval decision
92
+ */
93
+ async function promptForApproval(
94
+ filePath: string,
95
+ mode: 'read' | 'write' | 'search'
96
+ ): Promise<boolean> {
97
+ return new Promise((resolve) => {
98
+ // If readline is closed (e.g., non-TTY/piped input), auto-approve
99
+ if (isReadlineClosed) {
100
+ console.info(
101
+ `[${mode.toUpperCase()}] Access to ${filePath} auto-approved (non-interactive mode)`
102
+ );
103
+ resolve(true);
104
+ return;
105
+ }
106
+ rl.question(`[${mode.toUpperCase()}] Approve access to ${filePath}? (y/n): `, (answer) => {
107
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
108
+ });
109
+ });
110
+ }
111
+
112
+ async function runEditAIAgent() {
113
+ console.info('\n╔════════════════════════════════════════════════════════╗');
114
+ console.info('║ Edit Tool AI Agent - LangChain + OpenAI ║');
115
+ console.info('║ True autonomous agent with LLM reasoning ║');
116
+ console.info('╚════════════════════════════════════════════════════════╝\n');
117
+
118
+ // Check required environment variables
119
+ const openaiKey = process.env.OPENAI_API_KEY;
120
+ if (!openaiKey) {
121
+ console.error('❌ Error: OPENAI_API_KEY not set in .env');
122
+ console.info(' Set it: export OPENAI_API_KEY="sk-..."');
123
+ console.info(' Get one from: https://platform.openai.com/api-keys');
124
+ process.exit(1);
125
+ }
126
+
127
+ console.info('🤖 Using OpenAI (GPT-4o-mini) as the AI agent\n');
128
+
129
+ // Create a temp file for the agent to work with
130
+ const tempFile = path.join(__dirname, 'temp-agent-edit-demo.txt');
131
+ fs.writeFileSync(
132
+ tempFile,
133
+ `Project TODO List
134
+ ================
135
+ - TODO: Implement authentication module
136
+ - TODO: Add database migrations
137
+ - TODO: Write API documentation
138
+ - TODO: Set up CI/CD pipeline
139
+ `
140
+ );
141
+
142
+ try {
143
+ // Initialize Matimo with auto-discovery
144
+ console.info('🚀 Initializing Matimo...');
145
+ const matimo = await MatimoInstance.init({ autoDiscover: true });
146
+
147
+ // Set up approval callback for interactive approval
148
+ const approvalManager = getPathApprovalManager();
149
+ approvalManager.setApprovalCallback(promptForApproval);
150
+
151
+ // Get edit tool
152
+ console.info('💬 Loading edit tool...');
153
+ const matimoTools = matimo.listTools();
154
+ const editTools = matimoTools.filter((t) => t.name === 'edit') as ToolDefinition[];
155
+ console.info(`✅ Loaded ${editTools.length} edit tool(s)\n`);
156
+
157
+ if (editTools.length === 0) {
158
+ console.error('❌ Edit tool not found');
159
+ process.exit(1);
160
+ }
161
+
162
+ // Convert to LangChain tools using the built-in converter
163
+ const langchainTools = await convertToolsToLangChain(editTools, matimo);
164
+
165
+ // Initialize OpenAI LLM
166
+ console.info('🤖 Initializing OpenAI (GPT-4o-mini) LLM...');
167
+ const model = new ChatOpenAI({
168
+ modelName: 'gpt-4o-mini',
169
+ temperature: 0.7,
170
+ });
171
+
172
+ // Create agent
173
+ console.info('🔧 Creating agent...\n');
174
+ const agent = await createAgent({
175
+ model,
176
+ tools: langchainTools as any,
177
+ });
178
+
179
+ // Define agent tasks (natural language requests)
180
+ const userRequests = [
181
+ {
182
+ title: 'Example 1: Replace TODO with DONE',
183
+ request: `Mark the first authentication TODO as DONE in file ${tempFile}. Then describe what you did.`,
184
+ },
185
+ {
186
+ title: 'Example 2: Insert new item',
187
+ request: `Add a new TODO "Set up error logging" after line 5 in file ${tempFile}. Confirm the action and tell me how many lines were affected.`,
188
+ },
189
+ {
190
+ title: 'Example 3: List file content',
191
+ request: `Show me the current content of file ${tempFile} (use read tool if available, or describe the final state after your edits)`,
192
+ },
193
+ ];
194
+
195
+ console.info('🧪 Running AI Agent Tasks');
196
+ console.info('═'.repeat(60));
197
+ console.info(`📁 Working with: ${tempFile}\n`);
198
+
199
+ // Show initial file content
200
+ console.info('📄 Initial file content:');
201
+ console.info('─'.repeat(60));
202
+ console.info(fs.readFileSync(tempFile, 'utf-8'));
203
+ console.info('─'.repeat(60) + '\n');
204
+
205
+ // Run each task through the agent
206
+ for (const task of userRequests) {
207
+ console.info(`${task.title}`);
208
+ console.info('─'.repeat(60));
209
+ console.info(`👤 User: "${task.request}"\n`);
210
+
211
+ try {
212
+ const response = await agent.invoke({
213
+ messages: [
214
+ {
215
+ role: 'user',
216
+ content: task.request,
217
+ },
218
+ ],
219
+ });
220
+
221
+ // Get the last message from the agent
222
+ const lastMessage = response.messages[response.messages.length - 1];
223
+ if (lastMessage) {
224
+ const content =
225
+ typeof lastMessage.content === 'string'
226
+ ? lastMessage.content
227
+ : String(lastMessage.content);
228
+
229
+ console.info(`🤖 Agent: ${content || '(Tool executed successfully)'}\n`);
230
+ }
231
+ } catch (error) {
232
+ const errorMsg = error instanceof Error ? error.message : String(error);
233
+ console.info(`⚠️ Agent error: ${errorMsg}\n`);
234
+ }
235
+ }
236
+
237
+ console.info('═'.repeat(60));
238
+ console.info('\n📄 Final file content:');
239
+ console.info('─'.repeat(60));
240
+ console.info(fs.readFileSync(tempFile, 'utf-8'));
241
+ console.info('─'.repeat(60));
242
+
243
+ console.info('\n✨ AI Agent Examples Complete!\n');
244
+ console.info('Key Features:');
245
+ console.info(' ✅ Real LLM (OpenAI) decides which tools to use');
246
+ console.info(' ✅ Natural language requests, not API calls');
247
+ console.info(' ✅ LLM generates tool parameters based on context');
248
+ console.info(' ✅ Agentic reasoning and decision-making\n');
249
+ console.info('⚠️ Note on agent responses:');
250
+ console.info(' The agent DOES call the real LLM to decide which tool to use.');
251
+ console.info(' However, LangChain agents generate minimal responses when tools succeed.');
252
+ console.info(' The agent autonomously executes tools without verbose narration.\n');
253
+ } catch (error) {
254
+ console.error('❌ Error:', error instanceof Error ? error.message : String(error));
255
+ if (error instanceof Error && error.stack) {
256
+ console.error('Stack:', error.stack);
257
+ }
258
+ process.exit(1);
259
+ } finally {
260
+ // Clean up
261
+ if (fs.existsSync(tempFile)) {
262
+ fs.unlinkSync(tempFile);
263
+ }
264
+ if (!isReadlineClosed) {
265
+ rl.close();
266
+ isReadlineClosed = true;
267
+ }
268
+ }
269
+ }
270
+
271
+ // Run the AI agent
272
+ runEditAIAgent().catch(console.error);