Skip to content
Go To Dashboard

@sapiom/langchain

LangChain v1.x middleware for agent tracking

Terminal window
npm install @sapiom/langchain

Create Sapiom middleware for LangChain v1.x agents

This middleware automatically tracks:

  • Agent invocations (start/end lifecycle)
  • Model calls (token estimation, actual usage)
  • Tool calls (pre-authorization, payment retry)

Signature:

function createSapiomMiddleware(config?: SapiomMiddlewareConfig): AgentMiddleware<any, any, any>

Parameters:

NameTypeDescription
configSapiomMiddlewareConfig-

Returns: AgentMiddleware<any, any, any> - Middleware object compatible with LangChain createAgent

Example: Basic usage

const agent = createAgent({
model: "gpt-4",
tools: [getWeather],
middleware: [
createSapiomMiddleware({
apiKey: process.env.SAPIOM_API_KEY,
}),
],
});

Example: With configuration

createSapiomMiddleware({
apiKey: process.env.SAPIOM_API_KEY,
failureMode: "open", // or "closed"
traceId: "my-workflow",
agentName: "customer-support-bot",
})

Example: Per-invocation override

await agent.invoke(
{ messages: [...] },
{ context: { sapiomTraceId: "conversation-456" } }
);

Generate SDK-prefixed trace ID

Used when user doesn’t provide traceId in config. Creates a UUID v4 with “sdk-” prefix for clarity.

Signature:

function generateSDKTraceId(): string

Returns: string - SDK-generated trace identifier (format: sdk-{uuid})

Example:

const traceId = generateSDKTraceId();
// "sdk-a1b2c3d4-e5f6-7890-abcd-ef1234567890"

Check if error is authorization denied

Signature:

function isAuthorizationDenied(error: unknown): boolean

Parameters:

NameTypeDescription
errorunknown-

Returns: boolean - True if error is AuthorizationDeniedError

Check if error is an authorization denial or timeout

These errors should always be thrown regardless of failureMode, as they represent business logic decisions rather than system failures.

Signature:

function isAuthorizationDeniedOrTimeout(error: unknown): boolean

Parameters:

NameTypeDescription
errorunknown-

Returns: boolean - True if error is authorization denied or timeout

Detects if an error is an MCP payment required error (402)

MCP tools return payment errors as ToolException with specific format matching the x402-mcp spec.

Signature:

function isMCPPaymentError(error: unknown): boolean

Parameters:

NameTypeDescription
errorunknown-

Returns: boolean - True if error is MCP payment required

Extract payment data from MCP error

Parses x402 payment response from error message or structured content.

Signature:

function extractPaymentFromMCPError(error: Record<string, unknown>): X402PaymentResponse

Parameters:

NameTypeDescription
errorRecord<string, unknown>-

Returns: X402PaymentResponse - Parsed x402 payment response

Estimate input tokens from messages

Uses character-based heuristic (~4 chars per token). LangChain v1.x middleware doesn’t have direct access to model’s getNumTokens, so we use this generic approach.

Signature:

function estimateInputTokens(messages: { content?: unknown; }[]): number

Parameters:

NameTypeDescription
messages{ content?: unknown; }[]-

Returns: number - Estimated input token count

Extract model ID from model object

LangChain wraps models in ConfigurableModel, RunnableBinding, etc. We check _defaultConfig or cached instances for model ID.

Signature:

function getModelId(model: unknown, depth?: number): string

Parameters:

NameTypeDescription
modelunknown-
depthnumber-

Returns: string - Model identifier string

Extract actual token usage from model response

Checks standard LangChain usage_metadata first, falls back to response_metadata for older patterns.

Signature:

function extractActualTokens(result: unknown): TokenUsage | null

Parameters:

NameTypeDescription
resultunknown-

Returns: TokenUsage | null - Token usage or null if not available

Error thrown when transaction authorization is denied

Constructor:

new AuthorizationDeniedError(message: string, txId: string)
ParameterTypeDescription
messagestring-
txIdstring-

Configuration for Sapiom middleware

Extends: BaseSapiomIntegrationConfig

PropertyTypeRequiredDescription
traceIdstring | undefinedNoWorkflow trace identifier

Purpose:
- Groups related transactions (LLM calls + tool calls) under one trace
- Enables workflow cost tracking and duration analysis
- Allows correlation with your distributed tracing system

Behavior:
- Provided: Uses your ID (e.g., “checkout-123”, “user-456-conv”)
- Not provided: SDK auto-generates UUID with “sdk-” prefix

Per-invoke override via context:
- Pass different ID in context.sapiomTraceId
agentIdstring | undefinedNoAgent identifier (UUID or numeric ID like AG-001)

Purpose:
- Tags transactions with a specific agent for filtering and analytics
- Enables agent-level cost tracking and usage analysis

Behavior:
- Provided: Uses existing agent with this ID
- Agent must be ACTIVE to be used
- Cannot be used with agentName
agentNamestring | undefinedNoAgent name for find-or-create behavior

Purpose:
- Automatically creates agent if it doesn’t exist
- Convenient for dynamic agent creation
- Ensures consistent agent tagging across runs

Behavior:
- Provided: Finds existing agent by name or creates new ACTIVE agent
- Cannot be used with agentId
- Agents are tenant-scoped (unique per organization)

Context passed per-invocation to override middleware config

PropertyTypeRequiredDescription
sapiomTraceIdstring | undefinedNoOverride trace ID for this invocation
sapiomAgentIdstring | undefinedNoOverride agent ID for this invocation
sapiomAgentNamestring | undefinedNoOverride agent name for this invocation

State maintained by the middleware across agent lifecycle

PropertyTypeRequiredDescription
__sapiomTraceIdstring | undefinedNoCurrent trace ID for this agent execution
__sapiomAgentTxIdstring | undefinedNoAgent transaction ID (created in beforeAgent)
__sapiomStartTimenumber | undefinedNoStart time for duration tracking

x402 Payment Response Structure From x402-mcp specification

PropertyTypeRequiredDescription
x402VersionnumberYesx402 protocol version
accepts{ [key: string]: unknown; scheme: string; amount?: string; minAmount?: string; maxAmount?: string; unit?: string; to?: string; }[]YesAccepted payment methods

Token usage information

PropertyTypeRequiredDescription
promptTokensnumberYes-
completionTokensnumber | undefinedNo-
totalTokensnumber | undefinedNo-

Request facts (pre-execution, from beforeAgent)

PropertyTypeRequiredDescription
agentType"react" | "unknown"YesAgent type (react is standard for createAgent)
entryMethod"invoke" | "stream"YesEntry method
messageCountnumberYesNumber of input messages
timestampstringYesTimestamp

Response facts (post-execution, from afterAgent)

PropertyTypeRequiredDescription
successbooleanYesWhether execution succeeded
durationMsnumberYesTotal execution duration in ms
outputMessageCountnumberYesNumber of output messages

Error facts

PropertyTypeRequiredDescription
errorTypestringYesError type/name
errorMessagestringYesError message
elapsedMsnumberYesTime elapsed before error

Complete agent facts envelope

PropertyTypeRequiredDescription
source"langchain-agent"Yes-
version"v1"Yes-
sdk{ name: string; version: string; }Yes-
requestAgentRequestFactsYes-
responseAgentResponseFacts | undefinedNo-
errorAgentErrorFacts | undefinedNo-

Request facts (pre-execution, from wrapModelCall)

PropertyTypeRequiredDescription
modelIdstringYesModel identifier
estimatedInputTokensnumberYesEstimated input tokens
messageCountnumberYesNumber of messages in conversation
hasToolsbooleanYesWhether tools are available
toolCountnumberYesNumber of tools available
timestampstringYesTimestamp

Response facts (post-execution)

PropertyTypeRequiredDescription
actualInputTokensnumberYesActual input tokens from provider
actualOutputTokensnumberYesActual output tokens from provider
actualTotalTokensnumberYesTotal tokens
durationMsnumberYesExecution duration in ms
hadToolCallsbooleanYesWhether response included tool calls
toolCallCountnumber | undefinedNoNumber of tool calls in response
toolCallNamesstring[] | undefinedNoNames of tools called
finishReasonstring | undefinedNoFinish reason from provider

Error facts

PropertyTypeRequiredDescription
errorTypestringYesError type/name
errorMessagestringYesError message
elapsedMsnumberYesTime elapsed before error
httpStatusnumber | undefinedNoHTTP status if applicable

Complete model facts envelope

PropertyTypeRequiredDescription
source"langchain-llm"Yes-
version"v1"Yes-
sdk{ name: string; version: string; }Yes-
requestModelRequestFactsYes-
responseModelResponseFacts | undefinedNo-
errorModelErrorFacts | undefinedNo-

Request facts (pre-execution, from wrapToolCall)

PropertyTypeRequiredDescription
toolNamestringYesTool name
toolDescriptionstring | undefinedNoTool description
hasArgumentsbooleanYesWhether arguments were provided
argumentKeysstring[]YesArgument keys (not values - privacy!)
timestampstringYesTimestamp

Response facts (post-execution)

PropertyTypeRequiredDescription
successbooleanYesWhether execution succeeded
durationMsnumberYesExecution duration in ms
hasResultboolean | undefinedNoWhether result was returned
resultTypestring | undefinedNoType of result

Error facts

PropertyTypeRequiredDescription
errorTypestringYesError type/name
errorMessagestringYesError message
durationMsnumberYesTime elapsed before error
isMCPPaymentErrorboolean | undefinedNoWhether this was a payment required error

Complete tool facts envelope

PropertyTypeRequiredDescription
source"langchain-tool"Yes-
version"v1"Yes-
sdk{ name: string; version: string; }Yes-
requestToolRequestFactsYes-
responseToolResponseFacts | undefinedNo-
errorToolErrorFacts | undefinedNo-