@sapiom/langchain-classic
v0.2.1
Published
LangChain v0.x integration for Sapiom SDK (legacy)
Readme
@sapiom/langchain
⚠️ Beta Status: Currently in v0.x. API may change before v1.0.0. Production-ready and actively maintained.
LangChain integration for Sapiom SDK providing automatic cost tracking, authorization, and session management for LangChain agents, tools, and models.
Version Compatibility
| Package Version | LangChain Version | Status | |----------------|-------------------|---------| | v0.x | v0.3+ | ✅ Active | | v1.0 | v1.0+ | 🚧 Planned |
This package currently supports LangChain v0.x. LangChain v1.x support coming in SDK v1.0.
Installation
npm install @sapiom/langchainFeatures
- ✅ One-line integration: Replace
createReactAgentwithcreateSapiomReactAgent - ✅ Automatic transaction authorization and cost tracking
- ✅ Trace-based workflow grouping for agents, tools, and models
- ✅ Pre-emptive authorization before LLM calls
- ✅ Automatic payment handling for MCP tools (402 errors)
- ✅ Works with any LangChain model (OpenAI, Anthropic, etc.)
- ✅ Full TypeScript support
- ✅ Environment variable configuration
Quick Start
The easiest way to add Sapiom tracking to your LangChain agent:
import { createSapiomReactAgent } from '@sapiom/langchain';
import { ChatOpenAI } from '@langchain/openai';
// Just replace createReactAgent with createSapiomReactAgent
const agent = await createSapiomReactAgent(
{
llm: new ChatOpenAI({ model: 'gpt-4' }),
tools: [...yourTools]
},
{
apiKey: process.env.SAPIOM_API_KEY,
traceId: 'my-agent-session'
}
);
// All operations (model + tools) are automatically tracked
const result = await agent.invoke({
messages: [{ role: "user", content: "What's the weather?" }]
});That's it! createSapiomReactAgent automatically wraps your model and tools with Sapiom tracking.
Configuration
All Sapiom wrappers (models, tools, agents) support the following configuration options:
import { SapiomChatOpenAI, wrapSapiomTool, wrapSapiomAgent } from '@sapiom/langchain';
const config = {
// Required (or use SAPIOM_API_KEY environment variable)
apiKey: 'sk_...',
// Optional - Control
enabled: true, // Enable Sapiom handling (default: true)
failureMode: 'open', // 'open' | 'closed' (default: 'open')
// 'open': Allow operations if Sapiom fails (prioritizes availability)
// 'closed': Block operations if Sapiom fails (prioritizes security)
// Optional - Default metadata (applied to all operations)
agentName: 'my-agent', // Agent identifier
agentId: 'agent-123', // Agent UUID or numeric ID
serviceName: 'my-service', // Service name for transactions
traceId: 'trace-xyz', // Workflow trace identifier
traceExternalId: 'ext-456', // External trace identifier
};
// Apply to models
const model = new SapiomChatOpenAI({ model: 'gpt-4' }, config);
// Apply to tools
const tool = wrapSapiomTool(myTool, config);
// Apply to agents
const agent = wrapSapiomAgent(graph, config);Control Options
enabled
When false, disables Sapiom tracking entirely. The wrapped component behaves exactly like the original LangChain component.
const model = new SapiomChatOpenAI(
{ model: 'gpt-4' },
{ apiKey: 'sk_...', enabled: false }
);
// Behaves like regular ChatOpenAI - no trackingfailureMode
Controls behavior when Sapiom API fails (network errors, 5xx, timeouts, SDK bugs):
'open'(default): Logs error, continues without tracking (prioritizes availability)'closed': Throws error, blocks operation (prioritizes security)
Important: Authorization denials and timeouts always throw errors regardless of failureMode (these are business logic decisions, not system failures).
// Development/testing: Fail fast if Sapiom has issues
const model = new SapiomChatOpenAI(
{ model: 'gpt-4' },
{ apiKey: 'sk_...', failureMode: 'closed' }
);
// Production: Degrade gracefully if Sapiom has issues
const model = new SapiomChatOpenAI(
{ model: 'gpt-4' },
{ apiKey: 'sk_...', failureMode: 'open' } // default
);Per-Request Overrides
Override configuration for individual requests using metadata:
// Disable Sapiom for a specific call
await model.invoke("Public data", {
metadata: { __sapiomEnabled: false }
});
// Override trace ID for a specific call
await model.invoke("User query", {
metadata: { __sapiomTraceId: "conversation-456" }
});Usage
Agents (Recommended)
Use createSapiomReactAgent as a drop-in replacement for LangChain's createReactAgent. It automatically wraps your model and tools:
import { createSapiomReactAgent } from '@sapiom/langchain';
import { ChatOpenAI } from '@langchain/openai';
import { ChatAnthropic } from '@langchain/anthropic';
// Works with any LangChain model
const agent = await createSapiomReactAgent(
{
llm: new ChatOpenAI({ model: 'gpt-4' }),
// or: llm: new ChatAnthropic({ model: 'claude-3-5-sonnet-20241022' }),
tools: [...yourTools]
},
{
apiKey: process.env.SAPIOM_API_KEY,
traceId: 'my-agent-session',
agentName: 'customer-support-bot',
failureMode: 'open' // 'open' | 'closed'
}
);
// All operations (model + tools) grouped under one trace
await agent.invoke({
messages: [{ role: "user", content: "Hello" }]
});Advanced Usage
For more control, you can manually wrap individual components:
Models
Drop-in replacements for LangChain chat models:
import { SapiomChatOpenAI, SapiomChatAnthropic } from '@sapiom/langchain';
// OpenAI
const openai = new SapiomChatOpenAI(
{ model: 'gpt-4', openAIApiKey: process.env.OPENAI_API_KEY },
{ apiKey: process.env.SAPIOM_API_KEY }
);
// Anthropic
const anthropic = new SapiomChatAnthropic(
{ model: 'claude-3-5-sonnet-20241022', anthropicApiKey: process.env.ANTHROPIC_API_KEY },
{ apiKey: process.env.SAPIOM_API_KEY }
);Tools
Wrap existing tools or create new ones with Sapiom tracking:
import { wrapSapiomTool, sapiomTool } from '@sapiom/langchain';
import { DynamicStructuredTool } from '@langchain/core/tools';
import { z } from 'zod';
// Wrap existing tool
const existingTool = new DynamicStructuredTool({
name: "weather",
description: "Get weather for a city",
schema: z.object({ city: z.string() }),
func: async ({ city }) => `Weather in ${city}: Sunny`
});
const wrappedTool = wrapSapiomTool(existingTool, {
apiKey: process.env.SAPIOM_API_KEY,
serviceName: 'weather-api'
});
// Or create new tool with built-in tracking
const newTool = sapiomTool(
async ({ city }) => `Weather in ${city}: Sunny`,
{
name: "weather",
description: "Get weather for a city",
schema: z.object({ city: z.string() })
},
{
apiKey: process.env.SAPIOM_API_KEY,
serviceName: 'weather-api'
}
);Manual Agent Wrapping
If you need to wrap an existing agent graph:
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { wrapSapiomAgent, SapiomChatOpenAI } from '@sapiom/langchain';
// Create model and tools with Sapiom tracking
const model = new SapiomChatOpenAI(
{ model: 'gpt-4' },
{ apiKey: process.env.SAPIOM_API_KEY }
);
const tools = [
// ... your wrapped tools
];
// Create LangChain agent
const graph = await createReactAgent({ llm: model, tools });
// Wrap with Sapiom for unified trace tracking
const agent = wrapSapiomAgent(graph, {
apiKey: process.env.SAPIOM_API_KEY,
traceId: 'agent-workflow',
agentName: 'customer-support-bot',
failureMode: 'open'
});
// All operations (model + tools) grouped under one trace
await agent.invoke({ messages: [{ role: "user", content: "Hello" }] });Environment Variables
Automatically reads from environment:
SAPIOM_API_KEY(required)SAPIOM_BASE_URLorSAPIOM_API_URL(optional)SAPIOM_TIMEOUT(optional, in milliseconds)
License
MIT © Sapiom
