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.
- package/.env.example +36 -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 +128 -0
- package/edit/edit-factory.ts +120 -0
- package/edit/edit-langchain.ts +272 -0
- package/execute/execute-decorator.ts +49 -0
- package/execute/execute-factory.ts +46 -0
- package/execute/execute-langchain.ts +163 -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/package.json +58 -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 +250 -0
- package/read/read-decorator.ts +107 -0
- package/read/read-factory.ts +104 -0
- package/read/read-langchain.ts +253 -0
- package/search/search-decorator.ts +154 -0
- package/search/search-factory.ts +129 -0
- package/search/search-langchain.ts +215 -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/web/web-decorator.ts +52 -0
- package/web/web-factory.ts +70 -0
- package/web/web-langchain.ts +163 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* SLACK TOOLS - 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 Slack tools 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:
|
|
26
|
+
* SLACK_BOT_TOKEN=xoxb-xxxxxxxxxxxxx
|
|
27
|
+
* OPENAI_API_KEY=sk-xxxxxxxxxxxxx
|
|
28
|
+
*
|
|
29
|
+
* 2. Install dependencies:
|
|
30
|
+
* npm install
|
|
31
|
+
*
|
|
32
|
+
* USAGE:
|
|
33
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
34
|
+
* export SLACK_BOT_TOKEN=xoxb-xxxx
|
|
35
|
+
* export OPENAI_API_KEY=sk-xxxx
|
|
36
|
+
* npm run slack:langchain
|
|
37
|
+
*
|
|
38
|
+
* WHAT IT DOES:
|
|
39
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
40
|
+
* This example shows an AI agent that can:
|
|
41
|
+
* 1. List Slack channels
|
|
42
|
+
* 2. Send messages to channels
|
|
43
|
+
* 3. Search message history
|
|
44
|
+
* 4. Retrieve channel information
|
|
45
|
+
* 5. Respond naturally in conversation style
|
|
46
|
+
*
|
|
47
|
+
* Example conversation:
|
|
48
|
+
* User: "Send a test message to #general"
|
|
49
|
+
* AI Agent: "I'll send a test message to the general channel..."
|
|
50
|
+
* [AI Agent calls slack-send-message tool]
|
|
51
|
+
* AI Agent: "Done! Message sent successfully."
|
|
52
|
+
*
|
|
53
|
+
* ============================================================================
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
import 'dotenv/config';
|
|
57
|
+
import path from 'path';
|
|
58
|
+
import { fileURLToPath } from 'url';
|
|
59
|
+
import { createAgent } from 'langchain';
|
|
60
|
+
import { ChatOpenAI } from '@langchain/openai';
|
|
61
|
+
import { MatimoInstance, convertToolsToLangChain, ToolDefinition } from 'matimo';
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Run AI Agent with Slack tools
|
|
65
|
+
* The agent receives natural language requests and decides which Slack tools to use
|
|
66
|
+
*/
|
|
67
|
+
async function runSlackAIAgent() {
|
|
68
|
+
// Parse CLI arguments
|
|
69
|
+
const args = process.argv.slice(2);
|
|
70
|
+
let channelId = process.env.TEST_CHANNEL || 'C0000000000';
|
|
71
|
+
|
|
72
|
+
for (const arg of args) {
|
|
73
|
+
if (arg.startsWith('--channel:')) {
|
|
74
|
+
channelId = arg.split(':')[1];
|
|
75
|
+
} else if (arg.startsWith('--channel=')) {
|
|
76
|
+
channelId = arg.split('=')[1];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.info('\n╔════════════════════════════════════════════════════════╗');
|
|
81
|
+
console.info('║ Slack AI Agent - LangChain + OpenAI ║');
|
|
82
|
+
console.info('║ True autonomous agent with LLM reasoning ║');
|
|
83
|
+
console.info('╚════════════════════════════════════════════════════════╝\n');
|
|
84
|
+
|
|
85
|
+
// Check required environment variables
|
|
86
|
+
const botToken = process.env.SLACK_BOT_TOKEN;
|
|
87
|
+
if (!botToken) {
|
|
88
|
+
console.error('❌ Error: SLACK_BOT_TOKEN not set in .env');
|
|
89
|
+
console.info(' Set it: export SLACK_BOT_TOKEN="xoxb-..."');
|
|
90
|
+
console.info(' Get one from: https://api.slack.com/apps');
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const openaiKey = process.env.OPENAI_API_KEY;
|
|
95
|
+
if (!openaiKey) {
|
|
96
|
+
console.error('❌ Error: OPENAI_API_KEY not set in .env');
|
|
97
|
+
console.info(' Set it: export OPENAI_API_KEY="sk-..."');
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.info(`📍 Target Channel: ${channelId}`);
|
|
102
|
+
console.info(`🤖 Using OpenAI (GPT-4o-mini) as the AI agent\n`);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
// Initialize Matimo with auto-discovery
|
|
106
|
+
console.info('🚀 Initializing Matimo...');
|
|
107
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
108
|
+
|
|
109
|
+
// Get Slack tools and convert to LangChain format
|
|
110
|
+
console.info('💬 Loading Slack tools...');
|
|
111
|
+
const matimoTools = matimo.listTools();
|
|
112
|
+
const slackTools = matimoTools.filter((t) => t.name.startsWith('slack'));
|
|
113
|
+
console.info(`✅ Loaded ${slackTools.length} Slack tools\n`);
|
|
114
|
+
|
|
115
|
+
// Find an available channel before creating agent
|
|
116
|
+
console.info('📋 Finding an available channel...');
|
|
117
|
+
const listChannelsResult = await matimo.execute('slack-list-channels', {
|
|
118
|
+
types: 'public_channel,private_channel',
|
|
119
|
+
limit: 10,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const listData = (listChannelsResult as any).data || listChannelsResult;
|
|
123
|
+
let activeChannel = channelId;
|
|
124
|
+
|
|
125
|
+
if (listData.ok === true && listData.channels && listData.channels.length > 0) {
|
|
126
|
+
const defaultChannelExists = listData.channels.some((ch: any) => ch.id === channelId);
|
|
127
|
+
if (!defaultChannelExists) {
|
|
128
|
+
activeChannel = listData.channels[0].id;
|
|
129
|
+
console.info(
|
|
130
|
+
` Using first available channel: #${listData.channels[0].name} (${activeChannel})\n`
|
|
131
|
+
);
|
|
132
|
+
} else {
|
|
133
|
+
console.info(
|
|
134
|
+
` Using specified channel: #${listData.channels.find((ch: any) => ch.id === channelId)?.name} (${channelId})\n`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
console.info(` ⚠️ Could not list channels, using default: ${channelId}\n`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Convert to LangChain tools (select key ones for agent)
|
|
142
|
+
const keySlackTools = slackTools.filter((t) =>
|
|
143
|
+
[
|
|
144
|
+
'slack-send-message',
|
|
145
|
+
'slack-list-channels',
|
|
146
|
+
'slack_get_channel_history',
|
|
147
|
+
'slack_search_messages',
|
|
148
|
+
'slack_get_user_info',
|
|
149
|
+
].includes(t.name)
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// ✅ Convert Matimo tools to LangChain format using the new integration
|
|
153
|
+
const langchainTools = await convertToolsToLangChain(
|
|
154
|
+
keySlackTools as ToolDefinition[],
|
|
155
|
+
matimo,
|
|
156
|
+
{
|
|
157
|
+
SLACK_BOT_TOKEN: botToken,
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// Initialize OpenAI LLM
|
|
162
|
+
console.info('🤖 Initializing OpenAI (GPT-4o-mini) LLM...');
|
|
163
|
+
const model = new ChatOpenAI({
|
|
164
|
+
modelName: 'gpt-4o-mini',
|
|
165
|
+
temperature: 0.7,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Create agent
|
|
169
|
+
console.info('🔧 Creating agent...\n');
|
|
170
|
+
const agent = await createAgent({
|
|
171
|
+
model,
|
|
172
|
+
tools: langchainTools as any[], // Type casting for LangChain tools
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Define agent tasks (natural language requests)
|
|
176
|
+
const userRequests = [
|
|
177
|
+
{
|
|
178
|
+
title: 'Example 1: List channels',
|
|
179
|
+
request: 'What Slack channels are available in this workspace?',
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
title: 'Example 2: Send a message',
|
|
183
|
+
request: `Send a test message to channel ${activeChannel} saying "Hello from AI Agent! This message was sent autonomously."`,
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
title: 'Example 3: Get channel history',
|
|
187
|
+
request: `What are the recent messages in channel ${activeChannel}?`,
|
|
188
|
+
},
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
console.info('🧪 Running AI Agent Tasks');
|
|
192
|
+
console.info('═'.repeat(60));
|
|
193
|
+
|
|
194
|
+
// Run each task through the agent
|
|
195
|
+
for (const task of userRequests) {
|
|
196
|
+
console.info(`\n${task.title}`);
|
|
197
|
+
console.info('─'.repeat(60));
|
|
198
|
+
console.info(`👤 User: "${task.request}"\n`);
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const response = await agent.invoke({
|
|
202
|
+
messages: [
|
|
203
|
+
{
|
|
204
|
+
role: 'user',
|
|
205
|
+
content: task.request,
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Get the last message from the agent
|
|
211
|
+
const lastMessage = response.messages[response.messages.length - 1];
|
|
212
|
+
if (lastMessage) {
|
|
213
|
+
if (typeof lastMessage.content === 'string') {
|
|
214
|
+
console.info(`🤖 Agent: ${lastMessage.content}\n`);
|
|
215
|
+
} else {
|
|
216
|
+
console.info(`🤖 Agent:`, lastMessage.content, '\n');
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
} catch (error) {
|
|
220
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
221
|
+
console.info(`⚠️ Agent error: ${errorMsg}\n`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
console.info('═'.repeat(60));
|
|
226
|
+
console.info('✨ AI Agent Examples Complete!\n');
|
|
227
|
+
console.info('Key Features:');
|
|
228
|
+
console.info(' ✅ Real LLM (OpenAI) decides which tools to use');
|
|
229
|
+
console.info(' ✅ Natural language requests, not API calls');
|
|
230
|
+
console.info(' ✅ LLM generates tool parameters based on context');
|
|
231
|
+
console.info(' ✅ Agentic reasoning and decision-making\n');
|
|
232
|
+
} catch (error) {
|
|
233
|
+
console.error('❌ Error:', error instanceof Error ? error.message : String(error));
|
|
234
|
+
if (error instanceof Error && error.stack) {
|
|
235
|
+
console.error('Stack:', error.stack);
|
|
236
|
+
}
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Run the AI agent
|
|
242
|
+
runSlackAIAgent().catch(console.error);
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ES2020",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"resolveJsonModule": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"outDir": "./dist"
|
|
17
|
+
},
|
|
18
|
+
"include": ["agents/**/*.ts", "gmail/**/*.ts", "slack/**/*.ts"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { MatimoInstance, setGlobalMatimoInstance, tool } from '@matimo/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Example: Web tool using @tool decorator pattern
|
|
5
|
+
* Demonstrates class-based HTTP requests with automatic decoration
|
|
6
|
+
*/
|
|
7
|
+
class WebClient {
|
|
8
|
+
@tool('web')
|
|
9
|
+
async fetchUrl(url: string, timeout?: number): Promise<unknown> {
|
|
10
|
+
// Decorator automatically intercepts and executes via Matimo
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@tool('web')
|
|
15
|
+
async postData(url: string, body: string, headers?: Record<string, string>): Promise<unknown> {
|
|
16
|
+
// Decorator automatically intercepts and executes via Matimo
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function decoratorExample() {
|
|
22
|
+
// Set up decorator support with autoDiscover
|
|
23
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
24
|
+
setGlobalMatimoInstance(matimo);
|
|
25
|
+
|
|
26
|
+
console.info('=== Web Tool - Decorator Pattern ===\n');
|
|
27
|
+
|
|
28
|
+
const client = new WebClient();
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// Example 1: Fetch through decorated method
|
|
32
|
+
console.info('1. Fetching content via decorator\n');
|
|
33
|
+
const result1 = await client.fetchUrl('https://api.github.com/repos/tallclub/matimo');
|
|
34
|
+
console.info('Status:', (result1 as any).statusCode);
|
|
35
|
+
console.info('Size:', (result1 as any).contentLength);
|
|
36
|
+
console.info('---\n');
|
|
37
|
+
|
|
38
|
+
// Example 2: POST through decorated method
|
|
39
|
+
console.info('2. Posting data via decorator\n');
|
|
40
|
+
const result2 = await client.postData(
|
|
41
|
+
'https://httpbin.org/post',
|
|
42
|
+
JSON.stringify({ test: 'data' }),
|
|
43
|
+
{ 'Content-Type': 'application/json' }
|
|
44
|
+
);
|
|
45
|
+
console.info('Status:', (result2 as any).statusCode);
|
|
46
|
+
console.info('---\n');
|
|
47
|
+
} catch (error: any) {
|
|
48
|
+
console.error('Error:', error.message);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
decoratorExample();
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { MatimoInstance } from '@matimo/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Example: Web tool using factory pattern
|
|
5
|
+
* Demonstrates making HTTP requests and fetching web content
|
|
6
|
+
*/
|
|
7
|
+
async function webExample() {
|
|
8
|
+
// Initialize Matimo with autoDiscover to find all tools (core + providers)
|
|
9
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
10
|
+
|
|
11
|
+
console.info('=== Web Tool - Factory Pattern ===\n');
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// Example 1: Fetch GitHub API
|
|
15
|
+
console.info('1. Fetching GitHub API (public endpoint)\n');
|
|
16
|
+
const github = await matimo.execute('web', {
|
|
17
|
+
url: 'https://api.github.com/repos/tallclub/matimo',
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
console.info('Status Code:', (github as any).statusCode);
|
|
21
|
+
console.info('Content size:', (github as any).size);
|
|
22
|
+
// Content is already parsed as an object
|
|
23
|
+
const githubData =
|
|
24
|
+
typeof (github as any).content === 'string'
|
|
25
|
+
? JSON.parse((github as any).content)
|
|
26
|
+
: (github as any).content;
|
|
27
|
+
console.info('Repository:', githubData.full_name);
|
|
28
|
+
console.info('Description:', githubData.description);
|
|
29
|
+
console.info('---\n');
|
|
30
|
+
|
|
31
|
+
// Example 2: Fetch HTML content
|
|
32
|
+
console.info('2. Fetching HTML content\n');
|
|
33
|
+
const html = await matimo.execute('web', {
|
|
34
|
+
url: 'https://www.example.com',
|
|
35
|
+
timeout: 15000,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
console.info('Status Code:', (html as any).statusCode);
|
|
39
|
+
console.info('Content type:', (html as any).contentType);
|
|
40
|
+
console.info('Content size:', (html as any).size);
|
|
41
|
+
const htmlContent =
|
|
42
|
+
typeof (html as any).content === 'string'
|
|
43
|
+
? (html as any).content
|
|
44
|
+
: JSON.stringify((html as any).content);
|
|
45
|
+
console.info('Content preview:');
|
|
46
|
+
console.info(htmlContent.substring(0, 200));
|
|
47
|
+
console.info('---\n');
|
|
48
|
+
|
|
49
|
+
// Example 3: POST request
|
|
50
|
+
console.info('3. POST request (echo service)\n');
|
|
51
|
+
const post = await matimo.execute('web', {
|
|
52
|
+
url: 'https://httpbin.org/post',
|
|
53
|
+
method: 'POST',
|
|
54
|
+
body: JSON.stringify({ message: 'Hello from Matimo' }),
|
|
55
|
+
headers: { 'Content-Type': 'application/json' },
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
console.info('Status Code:', (post as any).statusCode);
|
|
59
|
+
const postContent =
|
|
60
|
+
typeof (post as any).content === 'string'
|
|
61
|
+
? (post as any).content
|
|
62
|
+
: JSON.stringify((post as any).content);
|
|
63
|
+
console.info('Response:', postContent.substring(0, 200));
|
|
64
|
+
console.info('---\n');
|
|
65
|
+
} catch (error: any) {
|
|
66
|
+
console.error('Error fetching web content:', error.message);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
webExample();
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* WEB 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 make HTTP requests
|
|
12
|
+
* 3. Generates appropriate URLs and methods based on context
|
|
13
|
+
* 4. Executes tools autonomously
|
|
14
|
+
* 5. Processes results and responds naturally
|
|
15
|
+
*
|
|
16
|
+
* SETUP:
|
|
17
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
18
|
+
* 1. Create .env file:
|
|
19
|
+
* OPENAI_API_KEY=sk-xxxxxxxxxxxxx
|
|
20
|
+
*
|
|
21
|
+
* 2. Install dependencies:
|
|
22
|
+
* npm install
|
|
23
|
+
*
|
|
24
|
+
* USAGE:
|
|
25
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
26
|
+
* export OPENAI_API_KEY=sk-xxxx
|
|
27
|
+
* npm run web:langchain
|
|
28
|
+
*
|
|
29
|
+
* ============================================================================
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import 'dotenv/config';
|
|
33
|
+
import { createAgent } from 'langchain';
|
|
34
|
+
import { ChatOpenAI } from '@langchain/openai';
|
|
35
|
+
import { MatimoInstance, convertToolsToLangChain, type ToolDefinition } from '@matimo/core';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Run AI Agent with Web tool
|
|
39
|
+
* The agent receives natural language requests and decides when to make HTTP requests
|
|
40
|
+
*/
|
|
41
|
+
async function runWebAIAgent() {
|
|
42
|
+
console.info('\n╔════════════════════════════════════════════════════════╗');
|
|
43
|
+
console.info('║ Web Tool AI Agent - LangChain + OpenAI ║');
|
|
44
|
+
console.info('║ True autonomous agent with LLM reasoning ║');
|
|
45
|
+
console.info('╚════════════════════════════════════════════════════════╝\n');
|
|
46
|
+
|
|
47
|
+
// Check required environment variables
|
|
48
|
+
const openaiKey = process.env.OPENAI_API_KEY;
|
|
49
|
+
if (!openaiKey) {
|
|
50
|
+
console.error('❌ Error: OPENAI_API_KEY not set in .env');
|
|
51
|
+
console.info(' Set it: export OPENAI_API_KEY="sk-..."');
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.info('🤖 Using OpenAI (GPT-4o-mini) as the AI agent\n');
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
// Initialize Matimo with auto-discovery
|
|
59
|
+
console.info('🚀 Initializing Matimo...');
|
|
60
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
61
|
+
|
|
62
|
+
// Get web tool
|
|
63
|
+
console.info('💬 Loading web tool...');
|
|
64
|
+
const matimoTools = matimo.listTools();
|
|
65
|
+
const webTool = matimoTools.filter((t) => t.name === 'web');
|
|
66
|
+
console.info(`✅ Loaded ${webTool.length} web tool(s)\n`);
|
|
67
|
+
|
|
68
|
+
if (webTool.length === 0) {
|
|
69
|
+
console.error('❌ Web tool not found');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Convert to LangChain tools using the built-in converter
|
|
74
|
+
const webTools = webTool as ToolDefinition[];
|
|
75
|
+
const langchainTools = await convertToolsToLangChain(webTools, matimo);
|
|
76
|
+
|
|
77
|
+
// Initialize OpenAI LLM
|
|
78
|
+
console.info('🤖 Initializing OpenAI (GPT-4o-mini) LLM...');
|
|
79
|
+
const model = new ChatOpenAI({
|
|
80
|
+
modelName: 'gpt-4o-mini',
|
|
81
|
+
temperature: 0.7,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Create agent
|
|
85
|
+
console.info('🔧 Creating agent...\n');
|
|
86
|
+
const agent = await createAgent({
|
|
87
|
+
model,
|
|
88
|
+
tools: langchainTools as any,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Define agent tasks (natural language requests)
|
|
92
|
+
const userRequests = [
|
|
93
|
+
{
|
|
94
|
+
title: 'Example 1: Fetch GitHub repository info',
|
|
95
|
+
request: 'Get information about the tallclub/matimo repository from GitHub API',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
title: 'Example 2: Check API status',
|
|
99
|
+
request: 'Make a request to the GitHub API and tell me what HTTP status code we get',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
title: 'Example 3: Fetch public data',
|
|
103
|
+
request: 'Get JSON data from a public REST API endpoint and summarize the response',
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
console.info('🧪 Running AI Agent Tasks');
|
|
108
|
+
console.info('═'.repeat(60) + '\n');
|
|
109
|
+
|
|
110
|
+
// Run each task through the agent
|
|
111
|
+
for (const task of userRequests) {
|
|
112
|
+
console.info(`${task.title}`);
|
|
113
|
+
console.info('─'.repeat(60));
|
|
114
|
+
console.info(`👤 User: "${task.request}"\n`);
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const response = await agent.invoke({
|
|
118
|
+
messages: [
|
|
119
|
+
{
|
|
120
|
+
role: 'user',
|
|
121
|
+
content: task.request,
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Get the last message from the agent
|
|
127
|
+
const lastMessage = response.messages[response.messages.length - 1];
|
|
128
|
+
if (lastMessage) {
|
|
129
|
+
const content =
|
|
130
|
+
typeof lastMessage.content === 'string'
|
|
131
|
+
? lastMessage.content
|
|
132
|
+
: String(lastMessage.content);
|
|
133
|
+
|
|
134
|
+
if (content && content.trim()) {
|
|
135
|
+
console.info(`🤖 Agent: ${content}\n`);
|
|
136
|
+
} else {
|
|
137
|
+
console.info('🤖 Agent: (Request completed successfully)\n');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
142
|
+
console.info(`⚠️ Agent error: ${errorMsg}\n`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.info('═'.repeat(60));
|
|
147
|
+
console.info('\n✨ AI Agent Examples Complete!\n');
|
|
148
|
+
console.info('Key Features:');
|
|
149
|
+
console.info(' ✅ Real LLM (OpenAI) decides which tools to use');
|
|
150
|
+
console.info(' ✅ Natural language requests, not API calls');
|
|
151
|
+
console.info(' ✅ LLM generates URLs and HTTP methods based on context');
|
|
152
|
+
console.info(' ✅ Agentic reasoning and decision-making\n');
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error('❌ Error:', error instanceof Error ? error.message : String(error));
|
|
155
|
+
if (error instanceof Error && error.stack) {
|
|
156
|
+
console.error('Stack:', error.stack);
|
|
157
|
+
}
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Run the AI agent
|
|
163
|
+
runWebAIAgent().catch(console.error);
|