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.
- package/.env.example +49 -0
- package/LICENSE +21 -0
- package/README.md +525 -0
- package/agents/decorator-pattern-agent.ts +368 -0
- package/agents/factory-pattern-agent.ts +253 -0
- package/agents/langchain-agent.ts +146 -0
- package/edit/edit-decorator.ts +178 -0
- package/edit/edit-factory.ts +138 -0
- package/edit/edit-langchain.ts +292 -0
- package/execute/execute-decorator.ts +49 -0
- package/execute/execute-factory.ts +46 -0
- package/execute/execute-langchain.ts +232 -0
- package/github/github-decorator.ts +326 -0
- package/github/github-factory.ts +355 -0
- package/github/github-langchain.ts +206 -0
- package/github/github-with-approval.ts +228 -0
- package/gmail/README.md +345 -0
- package/gmail/gmail-decorator.ts +216 -0
- package/gmail/gmail-factory.ts +231 -0
- package/gmail/gmail-langchain.ts +201 -0
- package/hubspot/README.md +316 -0
- package/hubspot/hubspot-decorator.ts +180 -0
- package/hubspot/hubspot-factory.ts +188 -0
- package/hubspot/hubspot-langchain.ts +222 -0
- package/logger-example.ts +40 -0
- package/mailchimp/README.md +321 -0
- package/mailchimp/mailchimp-decorator.ts +277 -0
- package/mailchimp/mailchimp-factory.ts +187 -0
- package/mailchimp/mailchimp-langchain.ts +155 -0
- package/notion/README.md +293 -0
- package/notion/notion-decorator.ts +275 -0
- package/notion/notion-factory.ts +256 -0
- package/notion/notion-langchain.ts +237 -0
- package/package.json +79 -0
- package/postgres/README.md +188 -0
- package/postgres/postgres-decorator.ts +198 -0
- package/postgres/postgres-factory.ts +180 -0
- package/postgres/postgres-langchain.ts +213 -0
- package/postgres/postgres-with-approval.ts +344 -0
- package/read/read-decorator.ts +154 -0
- package/read/read-factory.ts +121 -0
- package/read/read-langchain.ts +273 -0
- package/search/search-decorator.ts +206 -0
- package/search/search-factory.ts +146 -0
- package/search/search-langchain.ts +255 -0
- package/slack/README.md +339 -0
- package/slack/slack-decorator.ts +245 -0
- package/slack/slack-factory.ts +226 -0
- package/slack/slack-langchain.ts +242 -0
- package/tsconfig.json +20 -0
- package/twilio/README.md +309 -0
- package/twilio/twilio-decorator.ts +288 -0
- package/twilio/twilio-factory.ts +238 -0
- package/twilio/twilio-langchain.ts +218 -0
- package/web/web-decorator.ts +52 -0
- package/web/web-factory.ts +70 -0
- package/web/web-langchain.ts +163 -0
|
@@ -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,178 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MatimoInstance,
|
|
3
|
+
setGlobalMatimoInstance,
|
|
4
|
+
tool,
|
|
5
|
+
getGlobalApprovalHandler,
|
|
6
|
+
type ApprovalRequest,
|
|
7
|
+
} from '@matimo/core';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import * as readline from 'readline';
|
|
12
|
+
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create an interactive approval callback
|
|
17
|
+
*/
|
|
18
|
+
function createApprovalCallback() {
|
|
19
|
+
return async (request: ApprovalRequest): Promise<boolean> => {
|
|
20
|
+
const isInteractive = process.stdin.isTTY;
|
|
21
|
+
|
|
22
|
+
console.info('\n' + '='.repeat(70));
|
|
23
|
+
console.info('🔒 APPROVAL REQUIRED FOR FILE OPERATION');
|
|
24
|
+
console.info('='.repeat(70));
|
|
25
|
+
console.info(`\n📋 Tool: ${request.toolName}`);
|
|
26
|
+
console.info(`📝 Description: ${request.description || '(no description provided)'}`);
|
|
27
|
+
console.info(`\n📄 File Operation:`);
|
|
28
|
+
console.info(` Path: ${request.params.filePath}`);
|
|
29
|
+
console.info(` Operation: ${request.params.operation}`);
|
|
30
|
+
if (request.params.content) {
|
|
31
|
+
console.info(` Content: ${String(request.params.content).substring(0, 50)}...`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!isInteractive) {
|
|
35
|
+
console.info('\n❌ REJECTED - Non-interactive environment (no terminal)');
|
|
36
|
+
console.info('\n💡 To enable auto-approval in CI/scripts:');
|
|
37
|
+
console.info(' export MATIMO_AUTO_APPROVE=true');
|
|
38
|
+
console.info('\n💡 Or approve specific patterns:');
|
|
39
|
+
console.info(' export MATIMO_APPROVED_PATTERNS="edit"');
|
|
40
|
+
console.info('\n' + '='.repeat(70) + '\n');
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Interactive mode: prompt user
|
|
45
|
+
const rl = readline.createInterface({
|
|
46
|
+
input: process.stdin,
|
|
47
|
+
output: process.stdout,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
console.info('\n❓ User Action Required');
|
|
52
|
+
const question = ' Type "yes" to approve or "no" to reject: ';
|
|
53
|
+
|
|
54
|
+
rl.question(question, (answer) => {
|
|
55
|
+
const approved = answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y';
|
|
56
|
+
|
|
57
|
+
if (approved) {
|
|
58
|
+
console.info(' ✅ Operation APPROVED by user');
|
|
59
|
+
} else {
|
|
60
|
+
console.info(' ❌ Operation REJECTED by user');
|
|
61
|
+
}
|
|
62
|
+
console.info('='.repeat(70) + '\n');
|
|
63
|
+
|
|
64
|
+
rl.close();
|
|
65
|
+
resolve(approved);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Example: Edit tool using @tool decorator pattern
|
|
73
|
+
* Demonstrates class-based file editing with automatic decoration
|
|
74
|
+
*/
|
|
75
|
+
class FileEditor {
|
|
76
|
+
@tool('edit')
|
|
77
|
+
async replaceContent(
|
|
78
|
+
filePath: string,
|
|
79
|
+
operation: string,
|
|
80
|
+
content: string,
|
|
81
|
+
startLine: number,
|
|
82
|
+
endLine: number
|
|
83
|
+
): Promise<unknown> {
|
|
84
|
+
// Decorator automatically intercepts and executes via Matimo
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@tool('edit')
|
|
89
|
+
async insertContent(
|
|
90
|
+
filePath: string,
|
|
91
|
+
operation: string,
|
|
92
|
+
content: string,
|
|
93
|
+
startLine: number,
|
|
94
|
+
endLine: number
|
|
95
|
+
): Promise<unknown> {
|
|
96
|
+
// Decorator automatically intercepts and executes via Matimo
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function decoratorExample() {
|
|
102
|
+
// Set up decorator support with autoDiscover
|
|
103
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
104
|
+
setGlobalMatimoInstance(matimo);
|
|
105
|
+
|
|
106
|
+
// Configure centralized approval handler
|
|
107
|
+
const approvalHandler = getGlobalApprovalHandler();
|
|
108
|
+
approvalHandler.setApprovalCallback(createApprovalCallback());
|
|
109
|
+
|
|
110
|
+
console.info('\n' + '='.repeat(70));
|
|
111
|
+
console.info('🚀 Edit Tool - Decorator Pattern Example');
|
|
112
|
+
console.info('='.repeat(70));
|
|
113
|
+
|
|
114
|
+
// Show current approval mode
|
|
115
|
+
const autoApproveEnabled = process.env.MATIMO_AUTO_APPROVE === 'true';
|
|
116
|
+
const approvedPatterns = process.env.MATIMO_APPROVED_PATTERNS;
|
|
117
|
+
|
|
118
|
+
console.info('\n🔐 APPROVAL CONFIGURATION:');
|
|
119
|
+
if (autoApproveEnabled) {
|
|
120
|
+
console.info(' ✅ MATIMO_AUTO_APPROVE=true');
|
|
121
|
+
console.info(' → All destructive operations will be AUTO-APPROVED');
|
|
122
|
+
} else if (approvedPatterns) {
|
|
123
|
+
console.info(` ✅ MATIMO_APPROVED_PATTERNS="${approvedPatterns}"`);
|
|
124
|
+
console.info(' → Matching operations will be auto-approved');
|
|
125
|
+
} else {
|
|
126
|
+
console.info(' ⚠️ INTERACTIVE MODE ENABLED');
|
|
127
|
+
console.info(' → You will be prompted to approve file operations');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const editor = new FileEditor();
|
|
131
|
+
|
|
132
|
+
// Create a temp file for demonstration
|
|
133
|
+
const tempFile = path.join(__dirname, 'temp-demo-decorator.txt');
|
|
134
|
+
fs.writeFileSync(tempFile, 'Original line\nAnother line\nThird line\n');
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
// Example 1: Replace through decorated method
|
|
138
|
+
console.info('\n1️⃣ REPLACING CONTENT');
|
|
139
|
+
console.info('-'.repeat(70));
|
|
140
|
+
console.info('Replacing line 1 with: "Updated line"');
|
|
141
|
+
console.info('(This is a write operation - may require approval)\n');
|
|
142
|
+
const result1 = await editor.replaceContent(tempFile, 'replace', 'Updated line', 1, 1);
|
|
143
|
+
if (result1) {
|
|
144
|
+
console.info('✅ Edit Result:', (result1 as any).success);
|
|
145
|
+
console.info('📊 Lines Affected:', (result1 as any).linesAffected);
|
|
146
|
+
console.info('📝 File content:');
|
|
147
|
+
console.info(fs.readFileSync(tempFile, 'utf-8'));
|
|
148
|
+
}
|
|
149
|
+
console.info('---\n');
|
|
150
|
+
|
|
151
|
+
// Example 2: Insert through decorated method
|
|
152
|
+
console.info('2️⃣ INSERTING CONTENT');
|
|
153
|
+
console.info('-'.repeat(70));
|
|
154
|
+
console.info('Inserting "Inserted line" at line 1');
|
|
155
|
+
console.info('(This is a write operation - may require approval)\n');
|
|
156
|
+
const result2 = await editor.insertContent(tempFile, 'insert', 'Inserted line', 1, 0);
|
|
157
|
+
if (result2) {
|
|
158
|
+
console.info('✅ Insert Result:', (result2 as any).success);
|
|
159
|
+
console.info('📊 Lines Affected:', (result2 as any).linesAffected);
|
|
160
|
+
console.info('📝 File content:');
|
|
161
|
+
console.info(fs.readFileSync(tempFile, 'utf-8'));
|
|
162
|
+
}
|
|
163
|
+
console.info('---\n');
|
|
164
|
+
|
|
165
|
+
console.info('✅ Decorator example completed successfully');
|
|
166
|
+
} catch (error: any) {
|
|
167
|
+
console.error('❌ Error:', error.message);
|
|
168
|
+
} finally {
|
|
169
|
+
// Clean up temp file
|
|
170
|
+
if (fs.existsSync(tempFile)) {
|
|
171
|
+
fs.unlinkSync(tempFile);
|
|
172
|
+
console.info('\n🧹 Cleaned up temporary file');
|
|
173
|
+
}
|
|
174
|
+
console.info('');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
decoratorExample();
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { MatimoInstance, getGlobalApprovalHandler, type ApprovalRequest } from '@matimo/core';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import * as readline from 'readline';
|
|
6
|
+
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create an interactive approval callback for file operations
|
|
11
|
+
*/
|
|
12
|
+
function createApprovalCallback() {
|
|
13
|
+
return async (request: ApprovalRequest): Promise<boolean> => {
|
|
14
|
+
const isInteractive = process.stdin.isTTY;
|
|
15
|
+
|
|
16
|
+
console.info('\n' + '='.repeat(70));
|
|
17
|
+
console.info('🔒 APPROVAL REQUIRED FOR FILE OPERATION');
|
|
18
|
+
console.info('='.repeat(70));
|
|
19
|
+
console.info(`\n📋 Tool: ${request.toolName}`);
|
|
20
|
+
console.info(`📝 Description: ${request.description || '(no description provided)'}`);
|
|
21
|
+
console.info(`\n📄 File Operation:`);
|
|
22
|
+
console.info(` Path: ${request.params.filePath}`);
|
|
23
|
+
if (request.params.startLine) {
|
|
24
|
+
console.info(` Start Line: ${request.params.startLine}`);
|
|
25
|
+
}
|
|
26
|
+
if (request.params.endLine) {
|
|
27
|
+
console.info(` End Line: ${request.params.endLine}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!isInteractive) {
|
|
31
|
+
console.info('\n❌ REJECTED - Non-interactive environment (no terminal)');
|
|
32
|
+
console.info('\n💡 To enable auto-approval in CI/scripts:');
|
|
33
|
+
console.info(' export MATIMO_AUTO_APPROVE=true');
|
|
34
|
+
console.info('\n💡 Or approve specific patterns:');
|
|
35
|
+
console.info(' export MATIMO_APPROVED_PATTERNS="edit"');
|
|
36
|
+
console.info('\n' + '='.repeat(70) + '\n');
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Interactive mode: prompt user
|
|
41
|
+
const rl = readline.createInterface({
|
|
42
|
+
input: process.stdin,
|
|
43
|
+
output: process.stdout,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
console.info('\n❓ User Action Required');
|
|
48
|
+
const question = ' Type "yes" to approve or "no" to reject: ';
|
|
49
|
+
|
|
50
|
+
rl.question(question, (answer) => {
|
|
51
|
+
const approved = answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y';
|
|
52
|
+
|
|
53
|
+
if (approved) {
|
|
54
|
+
console.info(' ✅ Operation APPROVED by user');
|
|
55
|
+
} else {
|
|
56
|
+
console.info(' ❌ Operation REJECTED by user');
|
|
57
|
+
}
|
|
58
|
+
console.info('='.repeat(70) + '\n');
|
|
59
|
+
|
|
60
|
+
rl.close();
|
|
61
|
+
resolve(approved);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Example: Edit tool using factory pattern
|
|
69
|
+
* Demonstrates editing and modifying file contents with interactive approval
|
|
70
|
+
*/
|
|
71
|
+
async function editExample() {
|
|
72
|
+
// Initialize Matimo with autoDiscover to find all tools (core + providers)
|
|
73
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
74
|
+
|
|
75
|
+
// Configure centralized approval handler
|
|
76
|
+
const approvalHandler = getGlobalApprovalHandler();
|
|
77
|
+
approvalHandler.setApprovalCallback(createApprovalCallback());
|
|
78
|
+
|
|
79
|
+
console.info('=== Edit Tool - Factory Pattern (Interactive Approval) ===\n');
|
|
80
|
+
|
|
81
|
+
// Create a temp file for demonstration
|
|
82
|
+
const tempFile = path.join(__dirname, 'temp-demo.txt');
|
|
83
|
+
fs.writeFileSync(tempFile, 'Line 1\nLine 2\nLine 3\n');
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
// Example 1: Replace text in file (replace line 2)
|
|
87
|
+
console.info('1. Replacing content in file\n');
|
|
88
|
+
console.info('Original content:');
|
|
89
|
+
console.info(fs.readFileSync(tempFile, 'utf-8'));
|
|
90
|
+
console.info('---\n');
|
|
91
|
+
|
|
92
|
+
const result = await matimo.execute('edit', {
|
|
93
|
+
filePath: tempFile,
|
|
94
|
+
operation: 'replace',
|
|
95
|
+
content: 'Line 2 (Modified)',
|
|
96
|
+
startLine: 2,
|
|
97
|
+
endLine: 2,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if ((result as any).success) {
|
|
101
|
+
console.info('Edit Result:', (result as any).success);
|
|
102
|
+
console.info('Lines Affected:', (result as any).linesAffected);
|
|
103
|
+
console.info('\nModified content:');
|
|
104
|
+
console.info(fs.readFileSync(tempFile, 'utf-8'));
|
|
105
|
+
} else {
|
|
106
|
+
console.info('Edit denied:', (result as any).error);
|
|
107
|
+
}
|
|
108
|
+
console.info('---\n');
|
|
109
|
+
|
|
110
|
+
// Example 2: Insert new content
|
|
111
|
+
console.info('2. Inserting new line\n');
|
|
112
|
+
const insertResult = await matimo.execute('edit', {
|
|
113
|
+
filePath: tempFile,
|
|
114
|
+
operation: 'insert',
|
|
115
|
+
content: 'New inserted line',
|
|
116
|
+
startLine: 2,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if ((insertResult as any).success) {
|
|
120
|
+
console.info('Insert Result:', (insertResult as any).success);
|
|
121
|
+
console.info('Lines Affected:', (insertResult as any).linesAffected);
|
|
122
|
+
console.info('\nFinal content:');
|
|
123
|
+
console.info(fs.readFileSync(tempFile, 'utf-8'));
|
|
124
|
+
} else {
|
|
125
|
+
console.info('Insert denied:', (insertResult as any).error);
|
|
126
|
+
}
|
|
127
|
+
console.info('---\n');
|
|
128
|
+
} catch (error: any) {
|
|
129
|
+
console.error('Error editing file:', error.message);
|
|
130
|
+
} finally {
|
|
131
|
+
// Clean up temp file
|
|
132
|
+
if (fs.existsSync(tempFile)) {
|
|
133
|
+
fs.unlinkSync(tempFile);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
editExample();
|