LangChain Integration | Agent Tool Protocol
Skip to main content

LangChain Integration

Agent Tool Protocol provides first-class integration with LangChain and LangGraph, making it easy to build powerful AI agents with access to tools and APIs.

Installation

npm install @mondaydotcomorg/atp-langchain @mondaydotcomorg/atp-client langchain @langchain/core

LangChain Tools

Convert ATP APIs into LangChain tools automatically.

Basic Usage

import { createServer } from '@mondaydotcomorg/atp-server';
import { AgentToolProtocolClient } from '@mondaydotcomorg/atp-client';
import { ATPLangChainTools } from '@mondaydotcomorg/atp-langchain';
import { ChatAnthropic } from '@langchain/anthropic';
import { AgentExecutor, createToolCallingAgent } from 'langchain/agents';
import { ChatPromptTemplate } from '@langchain/core/prompts';

// 1. Create and configure ATP server
const server = createServer();

server.registerAPI('calculator', {
add: {
description: 'Add two numbers',
inputSchema: {
type: 'object',
properties: {
a: { type: 'number' },
b: { type: 'number' },
},
required: ['a', 'b'],
},
handler: async ({ a, b }) => a + b,
},
multiply: {
description: 'Multiply two numbers',
inputSchema: {
type: 'object',
properties: {
a: { type: 'number' },
b: { type: 'number' },
},
required: ['a', 'b'],
},
handler: async ({ a, b }) => a * b,
},
});

await server.listen(3333);

// 2. Create ATP client
const client = new AgentToolProtocolClient({
baseUrl: 'http://localhost:3333',
});

await client.init();
await client.connect();

// 3. Convert ATP APIs to LangChain tools
const tools = await ATPLangChainTools.fromClient(client);

// 4. Create LangChain agent
const llm = new ChatAnthropic({
modelName: 'claude-3-5-sonnet-20241022',
apiKey: process.env.ANTHROPIC_API_KEY,
});

const prompt = ChatPromptTemplate.fromMessages([
['system', 'You are a helpful assistant with access to calculator functions.'],
['human', '{input}'],
['placeholder', '{agent_scratchpad}'],
]);

const agent = createToolCallingAgent({
llm,
tools,
prompt,
});

const agentExecutor = new AgentExecutor({
agent,
tools,
});

// 5. Run the agent
const result = await agentExecutor.invoke({
input: 'What is (15 + 7) * 3?',
});

console.log(result.output);
// "The result is 66"

Tool Configuration

Filtering Tools

Only include specific APIs:

const tools = await ATPLangChainTools.fromClient(client, {
includeAPIs: ['calculator', 'users'], // Only these APIs
excludeAPIs: ['admin'], // Exclude these
});

Custom Tool Names

Customize how tools are named:

const tools = await ATPLangChainTools.fromClient(client, {
toolNameFormat: (apiGroup, functionName) => {
return `${apiGroup}_${functionName}`.toUpperCase();
},
});

// Tools will be named: CALCULATOR_ADD, CALCULATOR_MULTIPLY, etc.

Tool Metadata

Add metadata to tools:

const tools = await ATPLangChainTools.fromClient(client, {
toolMetadata: {
'calculator.add': {
tags: ['math', 'arithmetic'],
category: 'calculator',
},
},
});

LangGraph Integration

Build sophisticated multi-step agents with LangGraph.

Basic LangGraph Agent

import { StateGraph, END } from '@langchain/langgraph';
import { ATPLangChainTools } from '@mondaydotcomorg/atp-langchain';

// Define agent state
interface AgentState {
input: string;
chatHistory: Array<any>;
agentOutcome?: any;
intermediateSteps: Array<any>;
}

// Create tools
const tools = await ATPLangChainTools.fromClient(client);

// Define agent nodes
const callModel = async (state: AgentState) => {
const response = await llm.invoke(state.input);
return { agentOutcome: response };
};

const executeTools = async (state: AgentState) => {
const { agentOutcome } = state;

// Execute tool calls
const toolCalls = agentOutcome.tool_calls || [];
const toolOutputs = await Promise.all(
toolCalls.map(async (call: any) => {
const tool = tools.find(t => t.name === call.name);
if (!tool) throw new Error(`Tool ${call.name} not found`);

const output = await tool.invoke(call.args);
return { tool: call.name, output };
})
);

return {
intermediateSteps: [...state.intermediateSteps, ...toolOutputs],
};
};

// Define routing
const shouldContinue = (state: AgentState) => {
if (state.agentOutcome?.tool_calls?.length > 0) {
return 'tools';
}
return END;
};

// Build graph
const workflow = new StateGraph<AgentState>({
channels: {
input: null,
chatHistory: null,
agentOutcome: null,
intermediateSteps: null,
},
});

workflow.addNode('agent', callModel);
workflow.addNode('tools', executeTools);

workflow.setEntryPoint('agent');
workflow.addConditionalEdges('agent', shouldContinue, {
tools: 'tools',
[END]: END,
});
workflow.addEdge('tools', 'agent');

const app = workflow.compile();

// Run the agent
const result = await app.invoke({
input: 'Calculate (10 + 5) * 3 and explain your work',
chatHistory: [],
intermediateSteps: [],
});

Multi-Agent System

import { StateGraph } from '@langchain/langgraph';

// Create specialized agents for different tasks
const mathAgent = createToolCallingAgent({
llm,
tools: await ATPLangChainTools.fromClient(client, {
includeAPIs: ['calculator'],
}),
prompt: mathPrompt,
});

const dataAgent = createToolCallingAgent({
llm,
tools: await ATPLangChainTools.fromClient(client, {
includeAPIs: ['users', 'products', 'orders'],
}),
prompt: dataPrompt,
});

// Build multi-agent graph
interface MultiAgentState {
input: string;
currentAgent: 'router' | 'math' | 'data';
result?: string;
}

const routerNode = async (state: MultiAgentState) => {
// Determine which agent to use
const classification = await llm.invoke(
`Classify this request as 'math' or 'data': ${state.input}`
);

return {
currentAgent: classification.includes('math') ? 'math' : 'data',
};
};

const mathNode = async (state: MultiAgentState) => {
const result = await mathAgent.invoke({ input: state.input });
return { result: result.output };
};

const dataNode = async (state: MultiAgentState) => {
const result = await dataAgent.invoke({ input: state.input });
return { result: result.output };
};

const workflow = new StateGraph<MultiAgentState>({
channels: {
input: null,
currentAgent: null,
result: null,
},
});

workflow.addNode('router', routerNode);
workflow.addNode('math', mathNode);
workflow.addNode('data', dataNode);

workflow.setEntryPoint('router');
workflow.addConditionalEdges('router', (state) => state.currentAgent);
workflow.addEdge('math', END);
workflow.addEdge('data', END);

const multiAgentApp = workflow.compile();

// Use the multi-agent system
const result = await multiAgentApp.invoke({
input: 'What is 15 * 3?',
currentAgent: 'router',
});

LangChain Node (Server-Side Tools)

Execute LangChain agents on the server for better performance.

Server-Side Agent

import { LangChainNode } from '@mondaydotcomorg/atp-langchain';
import { createServer } from '@mondaydotcomorg/atp-server';

// Create server with LangChain node
const server = createServer();

// Register LangChain agent as an API
server.registerAPI('agent', {
analyze: {
description: 'Analyze data using AI agent',
inputSchema: {
type: 'object',
properties: {
query: { type: 'string' },
data: { type: 'object' },
},
required: ['query'],
},
handler: async ({ query, data }) => {
// Create LangChain agent
const agent = createToolCallingAgent({
llm,
tools: dataAnalysisTools,
prompt,
});

// Execute agent
const executor = new AgentExecutor({ agent, tools: dataAnalysisTools });
const result = await executor.invoke({
input: query,
data,
});

return result.output;
},
},
});

server.listen(3333);

Client Usage

const client = new AgentToolProtocolClient({
baseUrl: 'http://localhost:3333',
});

await client.init();
await client.connect();

// Call the server-side agent
const result = await client.execute(`
const analysis = await agent.analyze({
query: "What are the top 3 products by revenue?",
data: salesData,
});

return analysis;
`);

Advanced Patterns

Agent with Memory

import { BufferMemory } from 'langchain/memory';
import { ConversationChain } from 'langchain/chains';

const memory = new BufferMemory();

const tools = await ATPLangChainTools.fromClient(client);

const agent = createToolCallingAgent({
llm,
tools,
prompt,
});

const agentExecutor = new AgentExecutor({
agent,
tools,
memory,
});

// Multi-turn conversation
await agentExecutor.invoke({ input: 'Calculate 10 + 5' });
await agentExecutor.invoke({ input: 'Multiply that by 3' });
await agentExecutor.invoke({ input: 'What was the first calculation?' });

Streaming Responses

import { AgentExecutor } from 'langchain/agents';

const agentExecutor = new AgentExecutor({
agent,
tools,
});

// Stream agent responses
const stream = await agentExecutor.stream({
input: 'Calculate a complex equation step by step',
});

for await (const chunk of stream) {
console.log(chunk);
}

Error Handling and Retry

import { RetryAgent } from '@mondaydotcomorg/atp-langchain';

const tools = await ATPLangChainTools.fromClient(client);

const agent = new RetryAgent({
llm,
tools,
maxRetries: 3,
retryDelay: 1000,
onRetry: (attempt, error) => {
console.log(`Retry attempt ${attempt}: ${error.message}`);
},
});

const result = await agent.invoke({
input: 'Perform a complex calculation',
});

Tool Selection

Control which tools the agent can use:

import { ToolSelector } from '@mondaydotcomorg/atp-langchain';

const tools = await ATPLangChainTools.fromClient(client);

// Create tool selector
const selector = new ToolSelector({
tools,
strategy: 'similarity', // Use semantic similarity
maxTools: 5, // Max tools per invocation
});

// Agent automatically selects relevant tools
const agent = createToolCallingAgent({
llm,
tools: [], // Empty initially
prompt,
});

// Wrap with tool selection
const agentWithSelector = async (input: string) => {
// Select relevant tools based on input
const selectedTools = await selector.select(input);

// Create agent with selected tools
const contextAgent = createToolCallingAgent({
llm,
tools: selectedTools,
prompt,
});

return await new AgentExecutor({
agent: contextAgent,
tools: selectedTools,
}).invoke({ input });
};

Client Tools in LangChain

Use ATP client tools with LangChain:

import { AgentToolProtocolClient } from '@mondaydotcomorg/atp-client';
import { ATPLangChainTools } from '@mondaydotcomorg/atp-langchain';

const client = new AgentToolProtocolClient({
baseUrl: 'http://localhost:3333',
});

// Provide client tools
client.provideTools([
{
name: 'readFile',
namespace: 'filesystem',
description: 'Read a file from local filesystem',
inputSchema: {
type: 'object',
properties: {
path: { type: 'string' },
},
required: ['path'],
},
handler: async ({ path }) => {
const fs = await import('fs/promises');
return await fs.readFile(path, 'utf-8');
},
},
]);

await client.init();
await client.connect();

// Convert all tools (server + client) to LangChain
const tools = await ATPLangChainTools.fromClient(client);

// Agent can now use both server and client tools!
const agent = createToolCallingAgent({ llm, tools, prompt });

Integration with RAG

Combine ATP with Retrieval Augmented Generation:

import { VectorStoreRetriever } from '@langchain/core/vectorstores';
import { OpenAIEmbeddings } from '@langchain/openai';
import { MemoryVectorStore } from 'langchain/vectorstores/memory';

// Create vector store
const vectorStore = new MemoryVectorStore(new OpenAIEmbeddings());

// Add documents
await vectorStore.addDocuments([
{ pageContent: 'Document 1 content', metadata: {} },
{ pageContent: 'Document 2 content', metadata: {} },
]);

// Create retriever tool
const retrieverTool = {
name: 'search_documents',
description: 'Search relevant documents',
func: async (query: string) => {
const docs = await vectorStore.similaritySearch(query, 3);
return docs.map(d => d.pageContent).join('\n\n');
},
};

// Get ATP tools
const atpTools = await ATPLangChainTools.fromClient(client);

// Combine tools
const allTools = [...atpTools, retrieverTool];

// Create RAG agent
const agent = createToolCallingAgent({
llm,
tools: allTools,
prompt: ChatPromptTemplate.fromMessages([
['system', 'You have access to documents and APIs. Search documents first when needed.'],
['human', '{input}'],
['placeholder', '{agent_scratchpad}'],
]),
});

Best Practices

1. Tool Organization

// ✅ Good: Organized by domain
const userTools = await ATPLangChainTools.fromClient(client, {
includeAPIs: ['users'],
});

const orderTools = await ATPLangChainTools.fromClient(client, {
includeAPIs: ['orders'],
});

// Create specialized agents
const userAgent = createToolCallingAgent({ llm, tools: userTools, prompt: userPrompt });
const orderAgent = createToolCallingAgent({ llm, tools: orderTools, prompt: orderPrompt });

2. Error Handling

// ✅ Good: Comprehensive error handling
try {
const tools = await ATPLangChainTools.fromClient(client);
const agent = createToolCallingAgent({ llm, tools, prompt });
const executor = new AgentExecutor({ agent, tools });

const result = await executor.invoke({ input: query });
return result.output;
} catch (error) {
if (error.message.includes('timeout')) {
// Handle timeout
} else if (error.message.includes('rate limit')) {
// Handle rate limit
} else {
// General error handling
}
}

3. Performance Optimization

// ✅ Good: Cache tools
let cachedTools: any[] | null = null;

async function getTools() {
if (!cachedTools) {
cachedTools = await ATPLangChainTools.fromClient(client);
}
return cachedTools;
}

// Reuse tools across invocations
const tools = await getTools();

4. Prompt Engineering

// ✅ Good: Clear instructions
const prompt = ChatPromptTemplate.fromMessages([
[
'system',
`You are a helpful assistant with access to the following tools:
- calculator: For mathematical operations
- users: For user management
- orders: For order processing

Always:
1. Use the most specific tool for the task
2. Verify results before responding
3. Ask for clarification if needed`,
],
['human', '{input}'],
['placeholder', '{agent_scratchpad}'],
]);

Next Steps

Common Issues

Tools Not Found

Problem: LangChain agent can't find tools

Solution: Ensure client is connected before creating tools:

await client.init();
await client.connect(); // Important!
const tools = await ATPLangChainTools.fromClient(client);

Type Errors

Problem: TypeScript type errors with tools

Solution: Use proper types:

import { StructuredTool } from '@langchain/core/tools';

const tools: StructuredTool[] = await ATPLangChainTools.fromClient(client);

Performance Issues

Problem: Slow agent execution

Solution:

  1. Cache tools
  2. Use batch callbacks
  3. Limit tool selection
const tools = await ATPLangChainTools.fromClient(client, {
maxTools: 10, // Limit number of tools
});
Agent Tool Protocol | ATP - Code Execution for AI Agents