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,216 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* GMAIL TOOLS - DECORATOR PATTERN EXAMPLE
|
|
5
|
+
* ============================================================================
|
|
6
|
+
*
|
|
7
|
+
* PATTERN: Decorator Pattern with @tool
|
|
8
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
9
|
+
* Uses TypeScript @tool decorators to wrap Gmail tool calls in a class.
|
|
10
|
+
*
|
|
11
|
+
* Use this pattern when:
|
|
12
|
+
* ✅ Building class-based applications
|
|
13
|
+
* ✅ Encapsulating tool logic in services
|
|
14
|
+
* ✅ Adding custom methods that combine multiple tools
|
|
15
|
+
* ✅ Need reusable tool wrappers
|
|
16
|
+
* ✅ Object-oriented design preferred
|
|
17
|
+
*
|
|
18
|
+
* SETUP:
|
|
19
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
20
|
+
* 1. Create .env file:
|
|
21
|
+
* GMAIL_ACCESS_TOKEN=ya29.xxxxxxxxxxxxx
|
|
22
|
+
*
|
|
23
|
+
* 2. Same scopes as factory pattern
|
|
24
|
+
*
|
|
25
|
+
* USAGE:
|
|
26
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
27
|
+
* export GMAIL_ACCESS_TOKEN=your_token_here
|
|
28
|
+
* npm run gmail:decorator
|
|
29
|
+
*
|
|
30
|
+
* ============================================================================
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import 'dotenv/config';
|
|
34
|
+
import path from 'path';
|
|
35
|
+
import { fileURLToPath } from 'url';
|
|
36
|
+
import { MatimoInstance, tool, setGlobalMatimoInstance } from 'matimo';
|
|
37
|
+
|
|
38
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Decorator Pattern Agent - Uses @tool decorators for Gmail operations
|
|
42
|
+
*/
|
|
43
|
+
class DecoratorPatternAgent {
|
|
44
|
+
constructor(private matimo: MatimoInstance) {}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Gmail send-email tool - automatically executes via @tool decorator
|
|
48
|
+
*/
|
|
49
|
+
@tool('gmail-send-email')
|
|
50
|
+
async sendEmail(to: string, subject: string, body: string): Promise<unknown> {
|
|
51
|
+
// Decorator automatically calls: matimo.execute('gmail-send-email', { to, subject, body })
|
|
52
|
+
// Matimo automatically injects GMAIL_ACCESS_TOKEN from env vars
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Gmail list-messages tool - automatically executes via @tool decorator
|
|
58
|
+
*/
|
|
59
|
+
@tool('gmail-list-messages')
|
|
60
|
+
async listMessages(query?: string, maxResults?: number): Promise<unknown> {
|
|
61
|
+
// Decorator automatically calls: matimo.execute('gmail-list-messages', { query, maxResults })
|
|
62
|
+
// Matimo automatically injects GMAIL_ACCESS_TOKEN from env vars
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Gmail get-message tool - automatically executes via @tool decorator
|
|
68
|
+
*/
|
|
69
|
+
@tool('gmail-get-message')
|
|
70
|
+
async getMessage(message_id: string, format?: string): Promise<unknown> {
|
|
71
|
+
// Decorator automatically calls: matimo.execute('gmail-get-message', { message_id, format })
|
|
72
|
+
// Matimo automatically injects GMAIL_ACCESS_TOKEN from env vars
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Gmail create-draft tool - automatically executes via @tool decorator
|
|
78
|
+
*/
|
|
79
|
+
@tool('gmail-create-draft')
|
|
80
|
+
async createDraft(to: string, subject: string, body: string): Promise<unknown> {
|
|
81
|
+
// Decorator automatically calls: matimo.execute('gmail-create-draft', { to, subject, body })
|
|
82
|
+
// Matimo automatically injects GMAIL_ACCESS_TOKEN from env vars
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Gmail delete-message tool - automatically executes via @tool decorator
|
|
88
|
+
*/
|
|
89
|
+
@tool('gmail-delete-message')
|
|
90
|
+
async deleteMessage(message_id: string): Promise<unknown> {
|
|
91
|
+
// Decorator automatically calls: matimo.execute('gmail-delete-message', { message_id })
|
|
92
|
+
// Matimo automatically injects GMAIL_ACCESS_TOKEN from env vars
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Run decorator pattern examples
|
|
99
|
+
*/
|
|
100
|
+
async function runDecoratorPatternExamples() {
|
|
101
|
+
// Parse CLI arguments
|
|
102
|
+
const args = process.argv.slice(2);
|
|
103
|
+
let userEmail = process.env.TEST_EMAIL || 'test@example.com';
|
|
104
|
+
|
|
105
|
+
for (const arg of args) {
|
|
106
|
+
if (arg.startsWith('--email:')) {
|
|
107
|
+
userEmail = arg.split(':')[1];
|
|
108
|
+
} else if (arg.startsWith('--email=')) {
|
|
109
|
+
userEmail = arg.split('=')[1];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.info('\n╔════════════════════════════════════════════════════════╗');
|
|
114
|
+
console.info('║ Gmail Tools - Decorator Pattern ║');
|
|
115
|
+
console.info('║ (Uses @tool decorators for automatic execution) ║');
|
|
116
|
+
console.info('╚════════════════════════════════════════════════════════╝\n');
|
|
117
|
+
|
|
118
|
+
const accessToken = process.env.GMAIL_ACCESS_TOKEN;
|
|
119
|
+
if (!accessToken) {
|
|
120
|
+
console.error('❌ Error: GMAIL_ACCESS_TOKEN not set in .env');
|
|
121
|
+
console.info(' Set it: export GMAIL_ACCESS_TOKEN="ya29...."');
|
|
122
|
+
console.info(' Or get a token from: https://developers.google.com/oauthplayground');
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.info(`📧 User Email: ${userEmail}\n`);
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
// Initialize Matimo
|
|
130
|
+
console.info('🚀 Initializing Matimo...');
|
|
131
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
132
|
+
setGlobalMatimoInstance(matimo);
|
|
133
|
+
|
|
134
|
+
const matimoTools = matimo.listTools();
|
|
135
|
+
console.info(`📦 Loaded ${matimoTools.length} tools:\n`);
|
|
136
|
+
matimoTools.forEach((t) => {
|
|
137
|
+
console.info(` • ${t.name}`);
|
|
138
|
+
console.info(` ${t.description}\n`);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Create agent
|
|
142
|
+
const agent = new DecoratorPatternAgent(matimo);
|
|
143
|
+
|
|
144
|
+
console.info('🧪 Testing Gmail Tools with Decorator Pattern');
|
|
145
|
+
console.info('═'.repeat(60));
|
|
146
|
+
|
|
147
|
+
// Example 1: List Messages via decorator
|
|
148
|
+
console.info('\n📬 Example 1: List Messages via @tool Decorator');
|
|
149
|
+
console.info('─'.repeat(60));
|
|
150
|
+
try {
|
|
151
|
+
const listResult = await agent.listMessages('', 5);
|
|
152
|
+
console.info('✅ Messages retrieved successfully!');
|
|
153
|
+
if (typeof listResult === 'object' && listResult !== null) {
|
|
154
|
+
const data = listResult as any;
|
|
155
|
+
if (data.messages && Array.isArray(data.messages)) {
|
|
156
|
+
console.info(` Found ${data.messages.length} recent messages:`);
|
|
157
|
+
data.messages.slice(0, 3).forEach((msg: any, idx: number) => {
|
|
158
|
+
console.info(` ${idx + 1}. ID: ${msg.id.substring(0, 15)}...`);
|
|
159
|
+
});
|
|
160
|
+
} else {
|
|
161
|
+
console.info(' No messages or unexpected format');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.info(`⚠️ List failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Example 2: Send Email via decorator
|
|
169
|
+
console.info('\n📧 Example 2: Send Email via @tool Decorator');
|
|
170
|
+
console.info('─'.repeat(60));
|
|
171
|
+
try {
|
|
172
|
+
const sendResult = await agent.sendEmail(
|
|
173
|
+
userEmail,
|
|
174
|
+
'Hello from Decorator Pattern',
|
|
175
|
+
'This email was sent using the @tool decorator'
|
|
176
|
+
);
|
|
177
|
+
console.info('✅ Email sent successfully!');
|
|
178
|
+
if (typeof sendResult === 'object' && sendResult !== null) {
|
|
179
|
+
const data = sendResult as any;
|
|
180
|
+
if (data.id) console.info(` Message ID: ${data.id}`);
|
|
181
|
+
}
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.info(`⚠️ Send failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Example 3: Create Draft via decorator
|
|
187
|
+
console.info('\n✏️ Example 3: Create Draft via @tool Decorator');
|
|
188
|
+
console.info('─'.repeat(60));
|
|
189
|
+
try {
|
|
190
|
+
const draftResult = await agent.createDraft(
|
|
191
|
+
userEmail,
|
|
192
|
+
'Decorator Pattern Draft',
|
|
193
|
+
'This draft was created using the @tool decorator'
|
|
194
|
+
);
|
|
195
|
+
console.info('✅ Draft created successfully!');
|
|
196
|
+
if (typeof draftResult === 'object' && draftResult !== null) {
|
|
197
|
+
const data = draftResult as any;
|
|
198
|
+
if (data.id) console.info(` Draft ID: ${data.id}`);
|
|
199
|
+
}
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.info(`⚠️ Draft failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
console.info('\n' + '═'.repeat(60));
|
|
205
|
+
console.info('✨ Decorator Pattern Examples Complete!\n');
|
|
206
|
+
console.info('Usage:');
|
|
207
|
+
console.info(' npm run gmail:decorator');
|
|
208
|
+
console.info(' npm run gmail:decorator -- --email:your-email@gmail.com\n');
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.error('❌ Error:', error instanceof Error ? error.message : String(error));
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Run the examples
|
|
216
|
+
runDecoratorPatternExamples().catch(console.error);
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* GMAIL TOOLS - FACTORY PATTERN EXAMPLE
|
|
5
|
+
* ============================================================================
|
|
6
|
+
*
|
|
7
|
+
* PATTERN: SDK Factory Pattern
|
|
8
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
9
|
+
* Direct tool execution via MatimoInstance - the simplest way to use tools.
|
|
10
|
+
*
|
|
11
|
+
* Use this pattern when:
|
|
12
|
+
* ✅ Building simple scripts or CLI tools
|
|
13
|
+
* ✅ Direct API calls without abstraction
|
|
14
|
+
* ✅ Quick prototyping
|
|
15
|
+
* ✅ One-off tool execution
|
|
16
|
+
*
|
|
17
|
+
* SETUP:
|
|
18
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
19
|
+
* 1. Create .env file in project root:
|
|
20
|
+
* GMAIL_ACCESS_TOKEN=ya29.xxxxxxxxxxxxx
|
|
21
|
+
*
|
|
22
|
+
* 2. Get a Gmail access token:
|
|
23
|
+
* - Use OAuth2Handler to authenticate with Google
|
|
24
|
+
* - Request these scopes:
|
|
25
|
+
* • https://www.googleapis.com/auth/gmail.send (send emails)
|
|
26
|
+
* • https://www.googleapis.com/auth/gmail.readonly (read emails)
|
|
27
|
+
* • https://www.googleapis.com/auth/gmail.modify (drafts, delete)
|
|
28
|
+
*
|
|
29
|
+
* USAGE:
|
|
30
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
31
|
+
* export GMAIL_ACCESS_TOKEN=your_token_here
|
|
32
|
+
* npm run gmail:factory
|
|
33
|
+
*
|
|
34
|
+
* AVAILABLE TOOLS:
|
|
35
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
36
|
+
* 1. gmail-send-email
|
|
37
|
+
* Parameters: to (required), subject (required), body (required), [cc], [bcc]
|
|
38
|
+
* Returns: { id, threadId, labelIds }
|
|
39
|
+
* Example: Send an email to someone@example.com
|
|
40
|
+
*
|
|
41
|
+
* 2. gmail-list-messages
|
|
42
|
+
* Parameters: [query], [maxResults], [pageToken]
|
|
43
|
+
* Returns: { messages[], nextPageToken }
|
|
44
|
+
* Example queries: "is:unread", "from:someone@example.com", "has:attachment"
|
|
45
|
+
*
|
|
46
|
+
* 3. gmail-get-message
|
|
47
|
+
* Parameters: message_id, [format]
|
|
48
|
+
* Format options: "minimal" (lightweight), "full" (complete with headers)
|
|
49
|
+
* Returns: { payload { headers, body }, snippet }
|
|
50
|
+
*
|
|
51
|
+
* 4. gmail-create-draft
|
|
52
|
+
* Parameters: to, subject, body, [cc], [bcc]
|
|
53
|
+
* Returns: { id, message { id, threadId } }
|
|
54
|
+
* Note: Draft is created but not sent - user edits then sends manually
|
|
55
|
+
*
|
|
56
|
+
* 5. gmail-delete-message
|
|
57
|
+
* Parameters: message_id
|
|
58
|
+
* Returns: { success }
|
|
59
|
+
* Note: Permanently deletes the message
|
|
60
|
+
*
|
|
61
|
+
* ============================================================================
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
import 'dotenv/config';
|
|
65
|
+
import path from 'path';
|
|
66
|
+
import { fileURLToPath } from 'url';
|
|
67
|
+
import { MatimoInstance } from 'matimo';
|
|
68
|
+
|
|
69
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Run factory pattern examples
|
|
73
|
+
*/
|
|
74
|
+
async function runFactoryPatternExamples() {
|
|
75
|
+
// Parse CLI arguments
|
|
76
|
+
const args = process.argv.slice(2);
|
|
77
|
+
let userEmail = process.env.TEST_EMAIL || 'test@example.com';
|
|
78
|
+
|
|
79
|
+
for (const arg of args) {
|
|
80
|
+
if (arg.startsWith('--email:')) {
|
|
81
|
+
userEmail = arg.split(':')[1];
|
|
82
|
+
} else if (arg.startsWith('--email=')) {
|
|
83
|
+
userEmail = arg.split('=')[1];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.info('\n╔════════════════════════════════════════════════════════╗');
|
|
88
|
+
console.info('║ Gmail Tools - Factory Pattern ║');
|
|
89
|
+
console.info('║ (Direct execution - simplest approach) ║');
|
|
90
|
+
console.info('╚════════════════════════════════════════════════════════╝\n');
|
|
91
|
+
|
|
92
|
+
const accessToken = process.env.GMAIL_ACCESS_TOKEN;
|
|
93
|
+
if (!accessToken) {
|
|
94
|
+
console.error('❌ Error: GMAIL_ACCESS_TOKEN not set in .env');
|
|
95
|
+
console.info(' Set it: export GMAIL_ACCESS_TOKEN="ya29...."');
|
|
96
|
+
console.info(' Or get a token from: https://developers.google.com/oauthplayground');
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.info(`📧 User Email: ${userEmail}\n`);
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
// Initialize Matimo
|
|
104
|
+
console.info('🚀 Initializing Matimo...');
|
|
105
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
106
|
+
|
|
107
|
+
const matimoTools = matimo.listTools();
|
|
108
|
+
console.info(`📦 Loaded ${matimoTools.length} tools:\n`);
|
|
109
|
+
matimoTools.forEach((t) => {
|
|
110
|
+
console.info(` • ${t.name}`);
|
|
111
|
+
console.info(` ${t.description}\n`);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Filter to Gmail tools
|
|
115
|
+
const gmailTools = matimoTools.filter((t) => t.name.startsWith('gmail-'));
|
|
116
|
+
console.info(`📧 Found ${gmailTools.length} Gmail tools\n`);
|
|
117
|
+
|
|
118
|
+
console.info('🧪 Testing Gmail Tools with Factory Pattern');
|
|
119
|
+
console.info('═'.repeat(60));
|
|
120
|
+
|
|
121
|
+
// Example 1: List Messages (GET emails)
|
|
122
|
+
console.info('\n📬 Example 1: List Your Recent Messages');
|
|
123
|
+
console.info('─'.repeat(60));
|
|
124
|
+
try {
|
|
125
|
+
const listResult = await matimo.execute('gmail-list-messages', {
|
|
126
|
+
maxResults: 5,
|
|
127
|
+
GMAIL_ACCESS_TOKEN: accessToken,
|
|
128
|
+
});
|
|
129
|
+
console.info('📤 Raw Result:', JSON.stringify(listResult, null, 2));
|
|
130
|
+
|
|
131
|
+
if (typeof listResult === 'object' && listResult !== null) {
|
|
132
|
+
const data = listResult as any;
|
|
133
|
+
if (data.data?.messages && Array.isArray(data.data.messages)) {
|
|
134
|
+
console.info(`✅ Found ${data.data.messages.length} recent messages:`);
|
|
135
|
+
data.data.messages.slice(0, 3).forEach((msg: any, idx: number) => {
|
|
136
|
+
console.info(` ${idx + 1}. ID: ${msg.id}`);
|
|
137
|
+
console.info(` Thread: ${msg.threadId}`);
|
|
138
|
+
});
|
|
139
|
+
} else if (data.messages && Array.isArray(data.messages)) {
|
|
140
|
+
console.info(`✅ Found ${data.messages.length} recent messages:`);
|
|
141
|
+
data.messages.slice(0, 3).forEach((msg: any, idx: number) => {
|
|
142
|
+
console.info(` ${idx + 1}. ID: ${msg.id}`);
|
|
143
|
+
console.info(` Thread: ${msg.threadId}`);
|
|
144
|
+
});
|
|
145
|
+
} else {
|
|
146
|
+
console.info('❌ Unexpected response format');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.info(`❌ List failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
151
|
+
console.info(JSON.stringify(error, null, 2));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Example 2: Send Email
|
|
155
|
+
console.info('\n📧 Example 2: Send Email');
|
|
156
|
+
console.info('─'.repeat(60));
|
|
157
|
+
try {
|
|
158
|
+
// Simple API - just pass to, subject, body
|
|
159
|
+
// Matimo automatically converts to MIME format (defined in YAML)
|
|
160
|
+
const sendResult = await matimo.execute('gmail-send-email', {
|
|
161
|
+
to: userEmail,
|
|
162
|
+
subject: 'Hello from Matimo Factory Pattern',
|
|
163
|
+
body: 'This is a test email from the Factory pattern',
|
|
164
|
+
GMAIL_ACCESS_TOKEN: accessToken,
|
|
165
|
+
});
|
|
166
|
+
console.info('📤 Raw Result:', JSON.stringify(sendResult, null, 2));
|
|
167
|
+
|
|
168
|
+
if (typeof sendResult === 'object' && sendResult !== null) {
|
|
169
|
+
const data = sendResult as any;
|
|
170
|
+
if (data.data?.id) {
|
|
171
|
+
console.info(`✅ Email sent successfully!`);
|
|
172
|
+
console.info(` Message ID: ${data.data.id}`);
|
|
173
|
+
console.info(` Thread ID: ${data.data.threadId || 'N/A'}`);
|
|
174
|
+
} else if (data.id) {
|
|
175
|
+
console.info(`✅ Email sent successfully!`);
|
|
176
|
+
console.info(` Message ID: ${data.id}`);
|
|
177
|
+
console.info(` Thread ID: ${data.threadId || 'N/A'}`);
|
|
178
|
+
} else {
|
|
179
|
+
console.info('❌ Unexpected response format');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.info(`❌ Send failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
184
|
+
console.info(JSON.stringify(error, null, 2));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Example 3: Create Draft
|
|
188
|
+
console.info('\n✏️ Example 3: Create Draft');
|
|
189
|
+
console.info('─'.repeat(60));
|
|
190
|
+
try {
|
|
191
|
+
// Simple API - just pass to, subject, body
|
|
192
|
+
// Matimo automatically converts to MIME format (defined in YAML)
|
|
193
|
+
const draftResult = await matimo.execute('gmail-create-draft', {
|
|
194
|
+
to: userEmail,
|
|
195
|
+
subject: 'Factory Pattern Draft',
|
|
196
|
+
body: 'This is a draft created by the Factory pattern',
|
|
197
|
+
GMAIL_ACCESS_TOKEN: accessToken,
|
|
198
|
+
});
|
|
199
|
+
console.info('📤 Raw Result:', JSON.stringify(draftResult, null, 2));
|
|
200
|
+
|
|
201
|
+
if (typeof draftResult === 'object' && draftResult !== null) {
|
|
202
|
+
const data = draftResult as any;
|
|
203
|
+
if (data.data?.id) {
|
|
204
|
+
console.info(`✅ Draft created successfully!`);
|
|
205
|
+
console.info(` Draft ID: ${data.data.id}`);
|
|
206
|
+
console.info(` Message ID: ${data.data.message?.id || 'N/A'}`);
|
|
207
|
+
} else if (data.id) {
|
|
208
|
+
console.info(`✅ Draft created successfully!`);
|
|
209
|
+
console.info(` Draft ID: ${data.id}`);
|
|
210
|
+
} else {
|
|
211
|
+
console.info('❌ Unexpected response format');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
} catch (error) {
|
|
215
|
+
console.info(`❌ Draft failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
216
|
+
console.info(JSON.stringify(error, null, 2));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.info('\n' + '═'.repeat(60));
|
|
220
|
+
console.info('✨ Factory Pattern Examples Complete!\n');
|
|
221
|
+
console.info('Usage:');
|
|
222
|
+
console.info(' npm run gmail:factory');
|
|
223
|
+
console.info(' npm run gmail:factory -- --email:your-email@gmail.com\n');
|
|
224
|
+
} catch (error) {
|
|
225
|
+
console.error('❌ Error:', error instanceof Error ? error.message : String(error));
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Run the examples
|
|
231
|
+
runFactoryPatternExamples().catch(console.error);
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* GMAIL 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 Gmail tools to use from matimo
|
|
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
|
+
* GMAIL_ACCESS_TOKEN=ya29.xxxxxxxxxxxxx
|
|
27
|
+
* OPENAI_API_KEY=sk-xxxxxxxxxxxxx
|
|
28
|
+
*
|
|
29
|
+
* 2. Install dependencies:
|
|
30
|
+
* npm install
|
|
31
|
+
*
|
|
32
|
+
* USAGE:
|
|
33
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
34
|
+
* export GMAIL_ACCESS_TOKEN=your_token_here
|
|
35
|
+
* export OPENAI_API_KEY=your_openai_key_here
|
|
36
|
+
* pnpm gmail:langchain
|
|
37
|
+
*
|
|
38
|
+
* WHAT IT DOES:
|
|
39
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
40
|
+
* This example shows an AI agent that can:
|
|
41
|
+
* 1. Check your recent emails
|
|
42
|
+
* 2. Send emails to you based on LLM reasoning
|
|
43
|
+
* 3. Create draft emails with AI-generated content
|
|
44
|
+
* 4. Respond naturally in conversation style
|
|
45
|
+
*
|
|
46
|
+
* Example conversation:
|
|
47
|
+
* User: "Send me a test email"
|
|
48
|
+
* Claude: "I'll send you a test email now..."
|
|
49
|
+
* [Claude calls gmail-send-email tool]
|
|
50
|
+
* Claude: "Done! Email sent to your address."
|
|
51
|
+
*
|
|
52
|
+
* ============================================================================
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
import 'dotenv/config';
|
|
56
|
+
import path from 'path';
|
|
57
|
+
import { fileURLToPath } from 'url';
|
|
58
|
+
import { createAgent } from 'langchain';
|
|
59
|
+
import { ChatOpenAI } from '@langchain/openai';
|
|
60
|
+
import { MatimoInstance, convertToolsToLangChain, ToolDefinition } from 'matimo';
|
|
61
|
+
|
|
62
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Run AI Agent with Gmail tools
|
|
66
|
+
* The agent receives natural language requests and decides which Gmail tools to use
|
|
67
|
+
*/
|
|
68
|
+
async function runGmailAIAgent() {
|
|
69
|
+
// Parse CLI arguments
|
|
70
|
+
const args = process.argv.slice(2);
|
|
71
|
+
let userEmail = process.env.TEST_EMAIL || 'test@example.com';
|
|
72
|
+
|
|
73
|
+
for (const arg of args) {
|
|
74
|
+
if (arg.startsWith('--email:')) {
|
|
75
|
+
userEmail = arg.split(':')[1];
|
|
76
|
+
} else if (arg.startsWith('--email=')) {
|
|
77
|
+
userEmail = arg.split('=')[1];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.info('\n╔════════════════════════════════════════════════════════╗');
|
|
82
|
+
console.info('║ Gmail AI Agent - LangChain + OpenAI ║');
|
|
83
|
+
console.info('║ True autonomous agent with LLM reasoning ║');
|
|
84
|
+
console.info('╚════════════════════════════════════════════════════════╝\n');
|
|
85
|
+
|
|
86
|
+
// Check required environment variables
|
|
87
|
+
const accessToken = process.env.GMAIL_ACCESS_TOKEN;
|
|
88
|
+
if (!accessToken) {
|
|
89
|
+
console.error('❌ Error: GMAIL_ACCESS_TOKEN not set in .env');
|
|
90
|
+
console.info(' Set it: export GMAIL_ACCESS_TOKEN="ya29...."');
|
|
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(`📧 User Email: ${userEmail}`);
|
|
102
|
+
console.info(`🤖 Using OpenAI (GPT-4o-mini) as the AI agent\n`);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
// Initialize Matimo
|
|
106
|
+
console.info('🚀 Initializing Matimo...');
|
|
107
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
108
|
+
|
|
109
|
+
// Get Gmail tools and convert to LangChain format
|
|
110
|
+
console.info('📬 Loading Gmail tools...');
|
|
111
|
+
const matimoTools = matimo.listTools();
|
|
112
|
+
const gmailTools = matimoTools.filter((t) => t.name.startsWith('gmail-'));
|
|
113
|
+
console.info(`✅ Loaded ${gmailTools.length} Gmail tools\n`);
|
|
114
|
+
|
|
115
|
+
// Convert to LangChain tools
|
|
116
|
+
const langchainTools = await convertToolsToLangChain(gmailTools as ToolDefinition[], matimo, {
|
|
117
|
+
GMAIL_ACCESS_TOKEN: accessToken,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Initialize OpenAI LLM
|
|
121
|
+
console.info('🤖 Initializing OpenAI (GPT-4o-mini) LLM...');
|
|
122
|
+
const model = new ChatOpenAI({
|
|
123
|
+
modelName: 'gpt-4o-mini',
|
|
124
|
+
temperature: 0.7,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Create agent
|
|
128
|
+
console.info('🔧 Creating agent...\n');
|
|
129
|
+
const agent = await createAgent({
|
|
130
|
+
model,
|
|
131
|
+
tools: langchainTools as any[], // Type casting for LangChain tools
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Define agent tasks (natural language requests)
|
|
135
|
+
const userRequests = [
|
|
136
|
+
{
|
|
137
|
+
title: 'Example 1: Check recent emails',
|
|
138
|
+
request: 'How many recent emails do I have? List the first 3.',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
title: 'Example 2: Send a test email',
|
|
142
|
+
request: `Please send a test email to ${userEmail} with subject "Hello from AI Agent" and body "This email was sent by an AI agent using Matimo tools."`,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
title: 'Example 3: Create an automated draft',
|
|
146
|
+
request: `Create a draft email to ${userEmail} about "Weekly Summary" with a professional greeting and a summary of what this example demonstrated.`,
|
|
147
|
+
},
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
console.info('🧪 Running AI Agent Tasks');
|
|
151
|
+
console.info('═'.repeat(60));
|
|
152
|
+
|
|
153
|
+
// Run each task through the agent
|
|
154
|
+
for (const task of userRequests) {
|
|
155
|
+
console.info(`\n${task.title}`);
|
|
156
|
+
console.info('─'.repeat(60));
|
|
157
|
+
console.info(`👤 User: "${task.request}"\n`);
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
const response = await agent.invoke({
|
|
161
|
+
messages: [
|
|
162
|
+
{
|
|
163
|
+
role: 'user',
|
|
164
|
+
content: task.request,
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Get the last message from the agent
|
|
170
|
+
const lastMessage = response.messages[response.messages.length - 1];
|
|
171
|
+
if (lastMessage) {
|
|
172
|
+
if (typeof lastMessage.content === 'string') {
|
|
173
|
+
console.info(`🤖 Agent: ${lastMessage.content}\n`);
|
|
174
|
+
} else {
|
|
175
|
+
console.info(`🤖 Agent:`, lastMessage.content, '\n');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
180
|
+
console.info(`⚠️ Agent error: ${errorMsg}\n`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.info('═'.repeat(60));
|
|
185
|
+
console.info('✨ AI Agent Examples Complete!\n');
|
|
186
|
+
console.info('Key Features:');
|
|
187
|
+
console.info(' ✅ Real LLM (OpenAI) decides which tools to use');
|
|
188
|
+
console.info(' ✅ Natural language requests, not API calls');
|
|
189
|
+
console.info(' ✅ LLM generates tool parameters based on context');
|
|
190
|
+
console.info(' ✅ Agentic reasoning and decision-making\n');
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error('❌ Error:', error instanceof Error ? error.message : String(error));
|
|
193
|
+
if (error instanceof Error && error.stack) {
|
|
194
|
+
console.error('Stack:', error.stack);
|
|
195
|
+
}
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Run the AI agent
|
|
201
|
+
runGmailAIAgent().catch(console.error);
|