@notilens/langchain
v0.2.0
Published
NotiLens callback handler for LangChain.js — automatic run tracking, token metrics, and error alerting
Maintainers
Readme
@notilens/langchain
NotiLens callback handler for LangChain (JavaScript/TypeScript). Automatically tracks every chain, agent, LLM call, tool invocation, and retriever query — sending lifecycle events, token metrics, durations, and errors to NotiLens with zero manual instrumentation.
Installation
npm install @notilens/langchain @langchain/coreQuick start
import { NotiLensCallbackHandler } from '@notilens/langchain';
const handler = new NotiLensCallbackHandler({
name: 'my-app',
token: 'YOUR_TOKEN', // or set NOTILENS_TOKEN env var
secret: 'YOUR_SECRET', // or set NOTILENS_SECRET env var
});Attach to any chain, LLM, or agent executor — that's it:
// On a chain
const result = await chain.invoke(
{ input: '...' },
{ callbacks: [handler] }
);
// On an LLM
import { ChatOpenAI } from '@langchain/openai';
const llm = new ChatOpenAI({ model: 'gpt-4o', callbacks: [handler] });
// On an agent executor
await agentExecutor.invoke({ input: '...' }, { callbacks: [handler] });What gets tracked automatically
| Event | NotiLens action |
|---|---|
| Chain starts | run.start() |
| Chain completes | run.complete() |
| Chain errors | run.fail(error) |
| LLM / chat model called | run.progress("Calling gpt-4o with 3 messages…") |
| LLM response received | run.metric(prompt_tokens, completion_tokens, total_tokens) + duration |
| LLM timeout (> callTimeout) | run.timeout() |
| LLM error | run.error() |
| Agent uses a tool | run.loop("Agent step #N: using tool 'X'") + run.progress("Step N: using tool 'X'") |
| Agent finishes | run.complete(output) |
| Tool starts | run.progress("Running tool 'calculator'…") |
| Tool completes | run.progress("Tool completed") |
| Tool errors | run.error() |
| Retriever starts | run.progress("Retrieving context for: …") |
| Retriever returns docs | run.progress("Retrieved 5 documents") |
| Retriever errors | run.error() |
Configuration
const handler = new NotiLensCallbackHandler({
name: 'my-app', // name shown in NotiLens
token: 'YOUR_TOKEN', // NotiLens topic token
secret: 'YOUR_SECRET', // NotiLens topic secret
task: 'rag-pipeline', // fixed task label (default: chain class name)
callTimeout: 30, // LLM seconds before timeout event fires (default: 30)
sendOutput: true, // send final agent output as output.generated event (default: false)
maxOutputLength: 2000, // max characters of output to send (default: 2000)
});Custom metrics & events
// Numeric values accumulate across calls; strings are replaced
handler.metric('cost_usd', 0.004);
handler.metric('cache_hits', 1);
handler.metric('model', 'gpt-4o');
// Fire a custom event with optional level and metadata
handler.track('cache.hit', 'Retrieved from vector cache');
handler.track('guardrail.triggered', 'Blocked unsafe output', { level: 'warning' });
// Send a rich notification with URLs and tags
handler.notify('report.ready', 'Summary complete', {
downloadUrl: 'https://example.com/report.pdf',
tags: 'langchain,rag',
});
handler.notify('result.image', 'Chart generated', {
imageUrl: 'https://example.com/chart.png',
openUrl: 'https://example.com/dashboard',
});Note: Calling
metric(),track(), ornotify()when no chain is running logs a warning and does nothing:[NotiLens] handler.metric('cost_usd', ...) called with no active run — ignoring.
Reusing an existing NotiLens instance
import { NotiLens } from '@notilens/notilens';
import { NotiLensCallbackHandler } from '@notilens/langchain';
const nl = NotiLens.init('my-app', { token: '...', secret: '...' });
const handler = new NotiLensCallbackHandler({ nlAgent: nl });Environment variables
export NOTILENS_TOKEN="your_token"
export NOTILENS_SECRET="your_secret"// Token and secret picked up automatically
const handler = new NotiLensCallbackHandler({ name: 'my-app' });