Integrations: Langbase with Composio Tools
Let's take a look at how to integrate Langbase with Composio Tools.
In this integration guide, you will:
- Learn how to connect your Langbase Pipe Agents with Composio tools.
- Composio give you access to lots of real-world tools.
- Build agents that can execute tools from Slack, GitHub, Gmail, Linear, Notion, etc.
Think of Composio as the universal adapter for tools. It standardizes tools into simple function calls that your agents can understand.
- Pre-built tools for every major service
- Authentication handled automatically
Let's take a look at how to integrate Langbase with Composio Tools.
You'll need:
- Langbase account - Sign up here
- Composio account - Get your API key
- Node.js 18+ or Python 3.8+
Step #1
Install the SDKs
Install dependencies
npm install langbase @composio/core dotenv
Environment setup
Create a .env
file with your API keys:
.env
COMPOSIO_API_KEY="your_composio_api_key_here"
LANGBASE_API_KEY="your_langbase_api_key_here"
OPENAI_API_KEY="your_openai_api_key_here"
USER_ID="your_user_id_here"
ACCOUNT_ID="your_account_id_here"
Step #3
To connect Slack to Composio and enable tool access for your agent, follow these steps:
- Go to the Composio dashboard.
- In the navbar, click on
All Toolkits
button. - Search for Slack, open it.
- Inside the Slack toolkit, click
Add to Project
button. - Pick your authentication method OAuth2 or Bearer Token.
- After authentication click
Connect Account
button. - Enter the
External User ID
you want to associate with this Slack connection. - Enter the
Token
this is the Slack tokenxoxb-...
. - Once connected, your account will show up under connected accounts.
- After connecting, copy the generated Account ID (e.g.,
ca_xxxxxxxx
).
For a deeper walkthrough, check the Composio tools authentication docs.
Step #3
We'll create a Langbase Pipe that can use Slack tools through Composio.
Create the pipe
create-slack-agent.ts
import 'dotenv/config';
import { Langbase, Tools } from 'langbase';
import { Composio } from '@composio/core';
async function main() {
const langbase = new Langbase({
apiKey: process.env.LANGBASE_API_KEY!,
});
const composio = new Composio({
apiKey: process.env.COMPOSIO_API_KEY!
});
const userId = process.env.USER_ID!;
const accountId = process.env.ACCOUNT_ID!;
const tools = await composio.tools.get(userId, {
toolkits: ['slack'],
});
const rawTools = extractRawTools(tools);
const langbaseTools: Tools[] = rawTools
.filter(isValidFunctionTool)
.map(tool => ({
type: 'function' as const,
function: {
name: tool.function.name,
description: tool.function.description,
parameters: tool.function.parameters,
},
}));
await langbase.pipes.create({
name: 'slack-agent',
description: 'AI agent that can interact with Slack Workspaces',
model: 'openai:gpt-5-mini-2025-08-07',
tools: langbaseTools,
messages: [{
role: 'system',
content: `You are a helpful Slack assistant. You can execute the available tools to help users with Slack tasks.
Here are some things you can do:
- Send messages to channels or users
- Create and manage channels
- Look up user or channel information
- Automate reminders and notifications
- And more!
Always use the available tools to assist users with their Slack workspace needs.
If you are unsure, ask clarifying questions or suggest helpful actions.`,
}],
upsert: true
});
}
main();
// Robustly extract tools and validate structure for production readiness
function extractRawTools(tools: unknown): unknown[] {
if (Array.isArray(tools)) {
return tools;
}
if (tools && typeof tools === 'object' && 'tools' in tools && Array.isArray((tools as any).tools)) {
return (tools as { tools: unknown[] }).tools;
}
return [];
}
function isValidFunctionTool(
tool: unknown
): tool is { type: 'function'; function: { name: string; description?: string; parameters?: Record<string, unknown> } } {
if (
typeof tool !== 'object' ||
tool === null ||
(tool as any).type !== 'function' ||
typeof (tool as any).function !== 'object' ||
(tool as any).function === null ||
typeof (tool as any).function.name !== 'string'
) {
return false;
}
// Optionally, add more validation for parameters/description if needed
return true;
}
Step #4
Now the fun part. Let's run your Slack agent and see it in action.
run-agent.ts
import 'dotenv/config';
import { getToolsFromRun, Langbase, type Tools } from 'langbase';
import { Composio } from '@composio/core';
async function main() {
const langbase = new Langbase({
apiKey: process.env.LANGBASE_API_KEY!,
});
// 1. Initialize Composio.
const composio = new Composio({
apiKey: process.env.COMPOSIO_API_KEY!
});
const userId = process.env.USER_ID!;
const account_id = process.env.ACCOUNT_ID!;
const tools = await composio.tools.get(userId, {
toolkits: ['slack'],
});
const rawTools = extractRawTools(tools);
const langbaseTools: Tools[] = rawTools
.filter(isValidFunctionTool)
.map(tool => ({
type: 'function' as const,
function: {
name: tool.function.name,
description: tool.function.description,
parameters: tool.function.parameters,
},
}));
// You can uncomment this to create the pipe agent and change any parameters
// await createSlackAgent();
const response = await langbase.pipes.run({
name: 'slack-agent',
messages: [{
role: 'user',
content: 'Send hello in #social'
}],
stream: false,
tools: langbaseTools
});
const toolCalls = await getToolsFromRun(response);
const hasToolCalls = toolCalls.length > 0;
const threadId = response.threadId;
if (hasToolCalls) {
// Process each tool call
const toolResultPromises = toolCalls.map(async (toolCall): Promise<any> => {
const toolName = toolCall.function.name;
const toolParameters = JSON.parse(toolCall.function.arguments);
const toolResponse = await composio.tools.execute(toolName, {
userId: userId,
arguments: toolParameters,
connectedAccountId: account_id
});
return {
role: 'tool',
tool_call_id: toolCall.id,
content: JSON.stringify(toolResponse.data),
};
});
// Wait for all tool calls to complete
const toolResults = await Promise.all(toolResultPromises);
// Call the agent pipe again with the updated messages
const finalResponse = await langbase.pipes.run({
threadId,
stream: false,
name: 'slack-agent',
messages: toolResults,
tools: langbaseTools,
});
console.log('Final response:', finalResponse.completion);
}
async function createSlackAgent(){
await langbase.pipes.create({
name: 'slack-agent',
description: 'AI agent that can interact with Slack Workspaces',
model: 'openai:gpt-5-mini-2025-08-07',
tools: langbaseTools,
messages: [{
role: 'system',
content: `You are a helpful Slack assistant. You can execute the available tools to help users with Slack tasks.
Here are some things you can do:
- Send messages to channels or users
- Create and manage channels
- Look up user or channel information
- Automate reminders and notifications
- And more!
Always use the available tools to assist users with their Slack workspace needs.
If you are unsure, ask clarifying questions or suggest helpful actions.`,
}],
upsert: true
});
}
}
main();
// Robustly extract tools and validate structure for production readiness
function extractRawTools(tools: unknown): unknown[] {
if (Array.isArray(tools)) {
return tools;
}
if (tools && typeof tools === 'object' && 'tools' in tools && Array.isArray((tools as any).tools)) {
return (tools as { tools: unknown[] }).tools;
}
return [];
}
function isValidFunctionTool(
tool: unknown
): tool is { type: 'function'; function: { name: string; description?: string; parameters?: Record<string, unknown> } } {
if (
typeof tool !== 'object' ||
tool === null ||
(tool as any).type !== 'function' ||
typeof (tool as any).function !== 'object' ||
(tool as any).function === null ||
typeof (tool as any).function.name !== 'string'
) {
return false;
}
// Optionally, add more validation for parameters/description if needed
return true;
}
Using Langbase Memory to Retrieve Information and Send to Slack
You can combine Langbase's memory retrieval with your Slack agent to build more context-aware agents. For example, you might want to fetch a notes from memory, then send a summary or reminder to a Slack channel.
Here's a TypeScript example that demonstrates this workflow:
memory-to-slack.ts
import { Composio } from '@composio/core';
import 'dotenv/config';
import {getToolsFromRun, Langbase, Tools} from 'langbase';
const langbase = new Langbase({
apiKey: process.env.LANGBASE_API_KEY!,
});
async function main() {
const isMemoryExists = await langbase.memories.list().then((memories) => memories.find((memory) => memory.name === 'notes-slack'));
if (!isMemoryExists) {
// 1. Create the memory
await langbase.memories.create({
name: 'notes-slack',
embedding_model: 'openai:text-embedding-3-large'
});
// 2. Upload the document to the memory
await langbase.memories.documents.upload({
document: Buffer.from('Langbase is the most powerful serverless AI cloud for building and deploying AI agents.
Build, deploy, and scale serverless AI agents with tools and memory (RAG). Simple AI primitives no bloated frameworks, all with a world-class developer experience without using any frameworks.
'),
memoryName: 'notes-slack',
documentName: 'notes.txt',
contentType: 'text/plain',
});
}
// 3. Initialize Composio.
const composio = new Composio({
apiKey: process.env.COMPOSIO_API_KEY!
});
const userId = process.env.USER_ID!;
const account_id = process.env.ACCOUNT_ID!;
// 4. Get the tools from Composio
const tools = await composio.tools.get(userId, {
toolkits: ['slack'],
});
const rawTools = extractRawTools(tools);
// 5. Convert the tools to Langbase format
const langbaseTools: Tools[] = rawTools
.filter(isValidFunctionTool)
.map(tool => ({
type: 'function' as const,
function: {
name: tool.function.name,
description: tool.function.description,
parameters: tool.function.parameters,
},
}));
const memory = await langbase.memories.retrieve({
memory: [{name: 'notes-slack'}],
query: 'What is Langbase?',
});
console.log(memory);
// 6. Run the agent pipe
const response = await langbase.pipes.run({
name: 'slack-agent',
messages: [{
role: 'user',
content: `Send a message in #social with the summary of the notes : ${memory[0].text}`
}],
stream: false,
tools: langbaseTools
});
const toolCalls = await getToolsFromRun(response);
const hasToolCalls = toolCalls.length > 0;
const threadId = response.threadId;
if (hasToolCalls) {
// Process each tool call
const toolResultPromises = toolCalls.map(async (toolCall): Promise<any> => {
const toolName = toolCall.function.name;
const toolParameters = JSON.parse(toolCall.function.arguments);
const toolResponse = await composio.tools.execute(toolName, {
userId: userId,
arguments: toolParameters,
connectedAccountId: account_id
});
return {
role: 'tool',
tool_call_id: toolCall.id,
content: JSON.stringify(toolResponse.data),
};
});
// Wait for all tool calls to complete
const toolResults = await Promise.all(toolResultPromises);
// Call the agent pipe again with the updated messages
const finalResponse = await langbase.pipes.run({
threadId,
stream: false,
name: 'slack-agent',
messages: toolResults,
tools: langbaseTools,
});
console.log('Final response:', finalResponse.completion);
}
}
main();
function isValidFunctionTool(
tool: unknown
): tool is { type: 'function'; function: { name: string; description?: string; parameters?: Record<string, unknown> } } {
if (
typeof tool !== 'object' ||
tool === null ||
(tool as any).type !== 'function' ||
typeof (tool as any).function !== 'object' ||
(tool as any).function === null ||
typeof (tool as any).function.name !== 'string'
) {
return false;
}
// Optionally, add more validation for parameters/description if needed
return true;
}
function extractRawTools(tools: unknown): unknown[] {
if (Array.isArray(tools)) {
return tools;
}
if (tools && typeof tools === 'object' && 'tools' in tools && Array.isArray((tools as any).tools)) {
return (tools as { tools: unknown[] }).tools;
}
return [];
}
- Build something cool with Langbase APIs and SDK.
- Join our Discord community for feedback, requests, and support.