Tutorial 01: Simple Bridge
Learn the core concept of ai.matey by building your first Bridge.
What You’ll Build
Section titled “What You’ll Build”A simple Bridge that lets you write code in OpenAI’s format but execute it using Anthropic’s Claude API.
Time Required
Section titled “Time Required”⏱️ 10 minutes
Prerequisites
Section titled “Prerequisites”- Node.js 18+ installed
- One of these API keys:
- OpenAI API key, OR
- Anthropic API key
What is a Bridge?
Section titled “What is a Bridge?”A Bridge is the core concept of ai.matey. It connects a frontend adapter (your input format) with a backend adapter (the AI provider).
Your Code (OpenAI format) ↓Frontend Adapter (OpenAI) ↓Intermediate Representation ↓Backend Adapter (Anthropic) ↓Claude APIThis lets you write code once and switch providers without changing your application code.
Step 1: Install Packages
Section titled “Step 1: Install Packages”Create a new project and install the required packages:
mkdir my-first-bridgecd my-first-bridgenpm init -ynpm install ai.matey.core ai.matey.frontend ai.matey.backendStep 2: Create Your First Bridge
Section titled “Step 2: Create Your First Bridge”Create a file called index.js:
import { Bridge } from 'ai.matey.core';import { OpenAIFrontendAdapter } from 'ai.matey.frontend/openai';import { AnthropicBackendAdapter } from 'ai.matey.backend/anthropic';
// Create the bridgeconst bridge = new Bridge( new OpenAIFrontendAdapter(), // Input format: OpenAI new AnthropicBackendAdapter({ // Output provider: Anthropic apiKey: process.env.ANTHROPIC_API_KEY }));
// Make a request using OpenAI formatconst response = await bridge.chat({ model: 'gpt-4', // Any model name - will be mapped to Claude messages: [ { role: 'user', content: 'What is ai.matey?' } ]});
console.log(response.choices[0].message.content);Step 3: Set Your API Key
Section titled “Step 3: Set Your API Key”Create a .env file:
ANTHROPIC_API_KEY=your_api_key_hereStep 4: Run It
Section titled “Step 4: Run It”node index.jsYou should see Claude’s response in OpenAI format!
Understanding What Happened
Section titled “Understanding What Happened”- You wrote code using OpenAI’s API format (familiar to most developers)
- Frontend Adapter converted your request to the Intermediate Representation (IR)
- Backend Adapter converted the IR to Anthropic’s Claude API format
- Claude responded, and the backend adapter converted it back to IR
- Frontend Adapter converted IR back to OpenAI format
- You received an OpenAI-formatted response, even though Claude processed it
Why Is This Useful?
Section titled “Why Is This Useful?”1. Provider Independence
Section titled “1. Provider Independence”Change providers by only changing the backend:
// Switch to OpenAIconst bridge = new Bridge( new OpenAIFrontendAdapter(), new OpenAIBackendAdapter({ apiKey: process.env.OPENAI_API_KEY }));
// Or switch to Google Geminiconst bridge = new Bridge( new OpenAIFrontendAdapter(), new GeminiBackendAdapter({ apiKey: process.env.GEMINI_API_KEY }));Your application code stays exactly the same!
2. Format Independence
Section titled “2. Format Independence”You can also change the input format:
// Use Anthropic's format as inputconst bridge = new Bridge( new AnthropicFrontendAdapter(), new OpenAIBackendAdapter({ apiKey: process.env.OPENAI_API_KEY }));
// Write in Anthropic format, execute on OpenAIconst response = await bridge.chat({ model: 'claude-3-5-sonnet-20241022', max_tokens: 100, messages: [ { role: 'user', content: 'Hello!' } ]});3. Testing & Development
Section titled “3. Testing & Development”Use local models for development:
import { OllamaBackendAdapter } from 'ai.matey.backend/ollama';
const devBridge = new Bridge( new OpenAIFrontendAdapter(), new OllamaBackendAdapter({ baseURL: 'http://localhost:11434' }));Streaming Support
Section titled “Streaming Support”The Bridge also supports streaming responses:
const stream = await bridge.chatStream({ model: 'gpt-4', messages: [ { role: 'user', content: 'Count to 10' } ], stream: true});
for await (const chunk of stream) { const content = chunk.choices?.[0]?.delta?.content; if (content) { process.stdout.write(content); }}Error Handling
Section titled “Error Handling”Always wrap your Bridge calls in try-catch:
try { const response = await bridge.chat({ model: 'gpt-4', messages: [{ role: 'user', content: 'Hello!' }] }); console.log(response.choices[0].message.content);} catch (error) { console.error('Error:', error.message);}Common Patterns
Section titled “Common Patterns”Environment-Based Provider Selection
Section titled “Environment-Based Provider Selection”const backendAdapter = process.env.NODE_ENV === 'production' ? new AnthropicBackendAdapter({ apiKey: process.env.ANTHROPIC_API_KEY }) : new OllamaBackendAdapter({ baseURL: 'http://localhost:11434' });
const bridge = new Bridge( new OpenAIFrontendAdapter(), backendAdapter);Reusable Bridge Instance
Section titled “Reusable Bridge Instance”// Create onceconst bridge = new Bridge( new OpenAIFrontendAdapter(), new AnthropicBackendAdapter({ apiKey: process.env.ANTHROPIC_API_KEY }));
// Reuse many timesasync function chat(userMessage) { return await bridge.chat({ model: 'gpt-4', messages: [{ role: 'user', content: userMessage }] });}
const response1 = await chat('What is AI?');const response2 = await chat('Explain bridges');Troubleshooting
Section titled “Troubleshooting”“API key not found”
Section titled ““API key not found””Make sure your .env file has the correct API key and you’re using dotenv:
npm install dotenvimport 'dotenv/config';import { Bridge } from 'ai.matey.core';// ... rest of code“Module not found”
Section titled ““Module not found””Make sure you installed all packages:
npm install ai.matey.core ai.matey.frontend ai.matey.backend“Cannot use import statement”
Section titled ““Cannot use import statement””Add "type": "module" to your package.json:
{ "name": "my-first-bridge", "type": "module", "dependencies": { "ai.matey.core": "latest", "ai.matey.frontend": "latest", "ai.matey.backend": "latest" }}Next Steps
Section titled “Next Steps”Congratulations! You’ve built your first Bridge.
Continue learning:
- Tutorial 02: Using Middleware - Add logging, caching, and retry
- Examples on GitHub
- Core Concepts - Deep dive into architecture
Full Example Code
Section titled “Full Example Code”Here’s the complete working example:
import 'dotenv/config';import { Bridge } from 'ai.matey.core';import { OpenAIFrontendAdapter } from 'ai.matey.frontend/openai';import { AnthropicBackendAdapter } from 'ai.matey.backend/anthropic';
async function main() { // Create bridge const bridge = new Bridge( new OpenAIFrontendAdapter(), new AnthropicBackendAdapter({ apiKey: process.env.ANTHROPIC_API_KEY }) );
try { // Non-streaming example console.log('Non-streaming response:'); const response = await bridge.chat({ model: 'gpt-4', messages: [ { role: 'user', content: 'Explain ai.matey in one sentence' } ] }); console.log(response.choices[0].message.content);
// Streaming example console.log('\n\nStreaming response:'); const stream = await bridge.chatStream({ model: 'gpt-4', messages: [ { role: 'user', content: 'Count to 5' } ], stream: true });
for await (const chunk of stream) { const content = chunk.choices?.[0]?.delta?.content; if (content) { process.stdout.write(content); } } console.log('\n'); } catch (error) { console.error('Error:', error.message); }}
main();ANTHROPIC_API_KEY=sk-ant-...{ "name": "my-first-bridge", "version": "1.0.0", "type": "module", "dependencies": { "ai.matey.core": "latest", "ai.matey.frontend": "latest", "ai.matey.backend": "latest", "dotenv": "^16.0.0" }}Run it:
npm installnode index.jsReady for the next tutorial? Learn about Using Middleware