matimo-examples
v0.1.0-alpha.9
Published
Matimo SDK examples - Factory Pattern, Decorator Pattern, and LangChain integration with Slack and Gmail
Readme
Matimo + LangChain.js Agent Examples
Three complete, production-ready AI agent examples showing how to integrate Matimo SDK with LangChain.js.
🎯 What These Examples Demonstrate
✅ Framework-Independent Tool Execution:
- Matimo loads and manages tools independently
- Tools work the same way in any framework (LangChain, CrewAI, etc.)
- No tool redefinition needed across frameworks
- Simple adapter layer for LangChain integration
✅ Three SDK Calling Patterns:
LangChain Official API (Recommended): Use
createAgent()withtool()function- Simplest, fastest, most maintainable approach
- LangChain handles tool selection and calling automatically
- Use when: You want production-ready, framework-native integration
Decorator Pattern: Use
@tool(toolName)decorator on methods- Decorator intercepts calls → executes via Matimo
- Use when: You want method-based calling style
Factory Pattern: Direct
matimo.execute(toolName, params)calls- Call Matimo directly → tool executes
- Use when: You prefer functional style
✅ Full LangChain Integration:
- Real OpenAI GPT-4 agent with multi-step reasoning
- Tool orchestration with natural language understanding
- Matimo stays independent of LangChain's details
✅ Production Ready:
- Independent npm package setup
- Environment variable management
- Proper TypeScript configuration
- Clean imports from Matimo SDK
📦 Quick Start
1. Install Dependencies
npm installThis installs LangChain, Matimo SDK, and all required dependencies.
2. Setup Environment
# Copy environment template
cp .env.example .env
# Add your OpenAI API key
# Get key from: https://platform.openai.com/api-keys
echo "OPENAI_API_KEY=sk-your-key-here" >> .env3. Run LangChain Official API Agent (⭐ Recommended)
npm run agent:langchainWhat it does:
- Loads all tools from YAML using Matimo SDK
- Converts each tool to LangChain's native tool format
- Uses
createAgent()for automatic tool orchestration - LLM intelligently selects and executes tools
- Runs 3 example queries with real Matimo execution
Pattern:
LLM decides tool needed
↓
createAgent() invokes tool
↓
LangChain tool() wrapper executes
↓
Wrapper calls matimo.execute()
↓
Matimo executes via CommandExecutor or HttpExecutor
↓
Result flows back through LangChainWhy this approach is best:
- ✅ Minimal code (~100 lines)
- ✅ Pure LangChain API (no workarounds)
- ✅ Automatic schema generation from Zod
- ✅ Framework handles all complexity
- ✅ Matimo tools execute natively
- ✅ Production-ready out of the box
Example output:
❓ User: "🧮 What is 42 plus 8?"
🔌 [MATIMO] Executing tool via Matimo SDK: calculator
📥 [MATIMO] Input parameters: {"operation":"add","a":42,"b":8}
✅ [MATIMO] Execution successful
✅ Agent Response:
42 plus 8 equals 50.4. Run Decorator Pattern Agent
npm run agent:decoratorWhat it does:
- Loads all tools from YAML using Matimo SDK
- Creates agent with
@tool(toolName)decorated methods - Decorator intercepts method calls → executes via Matimo
- Uses dynamic dispatch to route tool calls to decorated methods
- No hardcoded routing - scales to any number of tools
- Runs 3 example queries
Pattern:
LLM decides tool name (string)
↓
executeTool(toolName, params)
↓
getToolMethodMap() maps name → method name
↓
Dynamically call decorated method
↓
@tool decorator intercepts
↓
Decorator calls matimo.execute()
↓
Matimo executes via CommandExecutor or HttpExecutor
↓
Result returned to agentWhy this approach is elegant:
- ✅ Decorated methods define agent's API clearly
- ✅ No if-else routing code (scales automatically)
- ✅ Add 100 tools = just add 100
@tool()decorated methods - ✅ Full type safety with TypeScript
- ✅ Decorator pattern working with real magic
- ✅ Dynamic dispatch handles routing
Example output:
❓ Prompt: "🧮 What is 42 plus 8?"
🔧 Using tool: calculator
Parameters: {"operation":"add","a":42,"b":8}
✅ Result: { result: 50 }5. Run Factory Pattern Agent
npm run agent:factoryWhat it does:
- Loads all tools from YAML (only those that actually exist)
- Directly calls
matimo.execute(toolName, params) - Simple, straightforward execution model
- Adapts to LangChain for agent orchestration
- Runs 3 example queries
Pattern:
Direct Matimo Call
↓
matimo.execute(toolName, params)
↓
Registry lookup & execution
↓
Result returned to LangChain🔀 Patterns Compared
| Aspect | LangChain Official | Decorator | Factory |
| -------------------- | -------------------------- | ----------------------------------- | ------------------------ |
| Call Style | createAgent() + tool() | await agent.method() | await matimo.execute() |
| Complexity | ~100 lines | ~200 lines (with dynamic dispatch) | ~150 lines |
| Schema | Automatic from Zod | Inferred from method signature | Manual mapping |
| Tool Binding | Native LangChain | Decorator intercept with reflection | Direct call |
| Scalability | ✅ Great | ✅ Excellent (no routing code) | ✅ Great |
| Type Safety | ✅ Yes | ✅ Yes (full TS support) | ✅ Yes |
| Recommended | ⭐ For frameworks | ⭐ For class-based agents | For functional style |
| Production Ready | ✅ Yes | ✅ Yes | ✅ Yes |
📁 Project Structure
examples/tools/
├── agents/
│ ├── langchain-agent.ts # ⭐ LangChain Official API (recommended)
│ ├── decorator-pattern-agent.ts # Uses @tool decorator with MatimoInstance
│ └── factory-pattern-agent.ts # Uses matimo.execute() with MatimoInstance
├── package.json # Standalone dependencies (LangChain, Matimo, etc.)
├── tsconfig.json # TypeScript configuration
├── .env.example # Environment template (OPENAI_API_KEY)
├── test-agents.ts # Testing script for tool verification
└── README.md # This file
All agents load tools from: `../../tools/` (parent project's tool definitions)
## 🔄 SDK Patterns Explained
## 🛠️ Converting Matimo Tools to LangChain
### Approach 1: Official LangChain API (⭐ Recommended)
Use LangChain's native `tool()` function with Zod schemas:
```typescript
import { tool } from 'langchain';
import { z } from 'zod';
import { MatimoInstance } from 'matimo';
// 1. Load Matimo tools
const matimo = await MatimoInstance.init('./tools');
// 2. Convert each Matimo tool to LangChain tool
function convertMatimoTool(matimo: MatimoInstance, toolName: string) {
const matimoTool = matimo.getTool(toolName);
// Build Zod schema from Matimo parameters
const schemaShape = {};
Object.entries(matimoTool.parameters).forEach(([paramName, param]) => {
let fieldSchema = z.string(); // Map Matimo types to Zod
if (!param.required) fieldSchema = fieldSchema.optional();
schemaShape[paramName] = fieldSchema;
});
// Create LangChain tool
return tool(
async (input) => {
// Execute via Matimo (the real tool execution)
const result = await matimo.execute(toolName, input);
return JSON.stringify(result);
},
{
name: matimoTool.name,
description: matimoTool.description,
schema: z.object(schemaShape),
}
);
}
// 3. Create agent with tools
const agent = await createAgent({
model: 'gpt-4o-mini',
tools: matimoTools.map(t => convertMatimoTool(matimo, t.name)),
});
// 4. Invoke agent
await agent.invoke({
messages: [{ role: 'user', content: 'What is 42 plus 8?' }],
});Why this works:
- ✅ LangChain handles all schema management
- ✅ Automatic parameter validation
- ✅ Native function calling with OpenAI
- ✅ Zero manual schema binding
- ✅ ~10 lines of tool conversion code
- ✅ All Matimo features preserved
Approach 2: Decorator Pattern
Use Matimo's @tool() decorator for method-based calling:
import { tool, setGlobalMatimoInstance, MatimoInstance } from 'matimo';
// 1. Load tools from YAML
const matimo = await MatimoInstance.init('./tools');
setGlobalMatimoInstance(matimo);
// 2. Define agent class with decorated methods
class MyAgent {
// @tool decorator intercepts call and executes via Matimo
@tool('calculator')
async calculator(operation: string, a: number, b: number) {
throw new Error('Decorator handles execution');
}
}
// 3. Call decorated method
const agent = new MyAgent();
const result = await agent.calculator('add', 5, 3); // Decorator intercepts → Matimo executesApproach 3: Factory Pattern
Use MatimoInstance.init() then direct execute() calls:
import { MatimoInstance } from 'matimo';
// 1. Initialize Matimo with tools directory
const matimo = await MatimoInstance.init('./tools');
// 2. List all available tools
const tools = matimo.listTools();
// 3. Execute tools directly
const result = await matimo.execute('calculator', {
operation: 'add',
a: 5,
b: 3,
});🔄 How It Works: Matimo + LangChain Integration
The beauty of Matimo is that it stays completely independent:
┌─────────────────────────────────────────────────────────┐
│ LangChain Agent (framework orchestration) │
│ │
│ LLM decides: "I need to use calculator tool" │
│ ↓ │
│ createAgent() invokes tool with user's params │
│ ↓ │
│ LangChain tool() wrapper receives params │
│ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Matimo Wrapper Function │ │
│ │ │ │
│ │ const result = await matimo.execute( │ │
│ │ 'calculator', │ │
│ │ { operation: 'add', a: 42, b: 8 } │ │
│ │ ); │ │
│ │ ↓ │ │
│ │ Matimo loads: tools/calculator.yaml │ │
│ │ Validates params against schema │ │
│ │ Executes: node calculator.js --op add 42 8 │ │
│ │ Parses output │ │
│ │ ↓ │ │
│ │ Returns: { result: 50 } │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ Wrapper returns JSON to LangChain │
│ ↓ │
│ LLM processes result: "42 + 8 = 50" │
└─────────────────────────────────────────────────────────┘Key insight: LangChain orchestrates tool selection, Matimo executes the tool.
- ✅ Matimo tools work the same in any framework
- ✅ No framework-specific tool reimplementation
- ✅ Add tool to
tools/*.yaml, it appears everywhere - ✅ Changes to tool YAML automatically reflect in all frameworks
✅ Verification: Matimo Executes, Not LangChain
When you run npm run agent:langchain, you'll see debug output confirming Matimo is executing:
❓ User: "🧮 What is 42 plus 8?"
🔌 [MATIMO] Executing tool via Matimo SDK: calculator
📥 [MATIMO] Input parameters: {"operation":"add","a":42,"b":8}
✅ [MATIMO] Execution successful
✅ Agent Response:
42 plus 8 equals 50.This proves:
- ✅ LangChain selected the
calculatortool - ✅ LangChain called the tool wrapper
- ✅ Matimo executed the actual tool (via CommandExecutor)
- ✅ Result flowed back through both frameworks
Not a LangChain tool—a Matimo tool executed through LangChain's orchestration.
🔑 Key Principles
"Define Tools ONCE, Use EVERYWHERE" - The Matimo Philosophy
Tools are defined in ../../tools/*.yaml ONCE:
# tools/calculator.yaml
name: calculator
description: Perform math operations
parameters:
operation:
type: string
enum: [add, subtract, multiply, divide]
a:
type: number
b:
type: number
execution:
type: command
command: node calculator.js
args: ['--op', '{operation}', '{a}', '{b}']These same tools are used in:
- ✅ This example: LangChain agents (via both patterns)
- ✅ Matimo SDK direct:
await matimo.execute('calculator', params) - ✅ MCP Server: Claude can call them natively
- ✅ REST API: HTTP endpoints (Phase 2)
- ✅ CLI: Command-line tool runner
- ✅ CrewAI, LlamaIndex, etc.: Framework integration
No duplication. No reimplementation. Pure reusability.
Both this example's agents use the exact same YAML tools - just different calling patterns.
🚀 Available Tools
These examples work with whatever tools are in ../../tools/:
| Tool | Type | Purpose |
| ------------ | ------- | ------------------------------------------------- |
| calculator | Command | Math operations (add, subtract, multiply, divide) |
| echo | Command | Echo messages back |
| http | HTTP | Make HTTP requests (GET, POST, etc.) |
Framework Independence: Add any tool to ../../tools/ and it automatically appears in all three agents. No code changes needed.
(See parent project's tools/ directory for all available tools)
🧪 Testing
All agents are fully testable. The parent project's test suite validates all tools:
# From parent project root
pnpm test test/integration/🐛 Troubleshooting
"Cannot find module 'matimo'"
Solution: Make sure parent project is built:
cd ../..
pnpm build
cd examples/tools
### "OPENAI_API_KEY is not set"
**Solution:** Create `.env` with your API key:
```bash
cp .env.example .env
# Edit .env and add your OpenAI API keyLangChain package errors
Solution: Reinstall all dependencies:
rm -rf node_modules package-lock.json
npm installTools not executing
Solution: Ensure parent project tools are compiled:
cd ../..
pnpm build
cd examples/tools
npm run agent:langchain # or agent:decorator, agent:factory📚 Next Steps
- Try all three agents - compare patterns:
npm run agent:langchain,agent:decorator,agent:factory - Modify agent queries in
agents/*.ts- change the example prompts - Add custom tools to
../../tools/- they auto-appear in all agents - Extend the agents - add memory, streaming, custom system prompts
- Deploy to production - use Matimo REST API or MCP server
🔗 Related Documentation
💡 Key Takeaway
This example proves Matimo's core value proposition:
Define tools ONCE in YAML ↓
Use them EVERYWHERE: LangChain (3 patterns), SDK, CrewAI, MCP, REST, CLI ↓
Zero duplication. Pure productivity.
All three agents use the exact same Matimo tools with different SDK patterns. That's the Matimo difference.
