Skip to content

Tutorial 01: Simple Bridge

Learn the core concept of ai.matey by building your first Bridge.

A simple Bridge that lets you write code in OpenAI’s format but execute it using Anthropic’s Claude API.

⏱️ 10 minutes

  • Node.js 18+ installed
  • One of these API keys:
    • OpenAI API key, OR
    • Anthropic API key

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 API

This lets you write code once and switch providers without changing your application code.

Create a new project and install the required packages:

Terminal window
mkdir my-first-bridge
cd my-first-bridge
npm init -y
npm install ai.matey.core ai.matey.frontend ai.matey.backend

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 bridge
const bridge = new Bridge(
new OpenAIFrontendAdapter(), // Input format: OpenAI
new AnthropicBackendAdapter({ // Output provider: Anthropic
apiKey: process.env.ANTHROPIC_API_KEY
})
);
// Make a request using OpenAI format
const 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);

Create a .env file:

Terminal window
ANTHROPIC_API_KEY=your_api_key_here
Terminal window
node index.js

You should see Claude’s response in OpenAI format!

  1. You wrote code using OpenAI’s API format (familiar to most developers)
  2. Frontend Adapter converted your request to the Intermediate Representation (IR)
  3. Backend Adapter converted the IR to Anthropic’s Claude API format
  4. Claude responded, and the backend adapter converted it back to IR
  5. Frontend Adapter converted IR back to OpenAI format
  6. You received an OpenAI-formatted response, even though Claude processed it

Change providers by only changing the backend:

// Switch to OpenAI
const bridge = new Bridge(
new OpenAIFrontendAdapter(),
new OpenAIBackendAdapter({ apiKey: process.env.OPENAI_API_KEY })
);
// Or switch to Google Gemini
const bridge = new Bridge(
new OpenAIFrontendAdapter(),
new GeminiBackendAdapter({ apiKey: process.env.GEMINI_API_KEY })
);

Your application code stays exactly the same!

You can also change the input format:

// Use Anthropic's format as input
const bridge = new Bridge(
new AnthropicFrontendAdapter(),
new OpenAIBackendAdapter({ apiKey: process.env.OPENAI_API_KEY })
);
// Write in Anthropic format, execute on OpenAI
const response = await bridge.chat({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 100,
messages: [
{ role: 'user', content: 'Hello!' }
]
});

Use local models for development:

import { OllamaBackendAdapter } from 'ai.matey.backend/ollama';
const devBridge = new Bridge(
new OpenAIFrontendAdapter(),
new OllamaBackendAdapter({
baseURL: 'http://localhost:11434'
})
);

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);
}
}

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);
}
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
);
// Create once
const bridge = new Bridge(
new OpenAIFrontendAdapter(),
new AnthropicBackendAdapter({ apiKey: process.env.ANTHROPIC_API_KEY })
);
// Reuse many times
async 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');

Make sure your .env file has the correct API key and you’re using dotenv:

Terminal window
npm install dotenv
import 'dotenv/config';
import { Bridge } from 'ai.matey.core';
// ... rest of code

Make sure you installed all packages:

Terminal window
npm install ai.matey.core ai.matey.frontend ai.matey.backend

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"
}
}

Congratulations! You’ve built your first Bridge.

Continue learning:

Here’s the complete working example:

index.js
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();
.env
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:

Terminal window
npm install
node index.js

Ready for the next tutorial? Learn about Using Middleware