npm package: @notilens/langchain
Description: NotiLens callback handler for LangChain — automatic run tracking, token metrics, and error alerting
Author: NotiLens
Latest version: 0.1.5

# @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

```bash
npm install @notilens/langchain @langchain/core
```

## Quick start

```ts
import { NotiLensCallbackHandler } from '@notilens/langchain';

const handler = new NotiLensCallbackHandler({
  agent: 'my-agent',
  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:

```ts
// 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.progress("Step N: using tool 'web_search' → query…")` |
| Agent loops (> `loopThreshold` steps) | `run.loop()` |
| 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

```ts
const handler = new NotiLensCallbackHandler({
  agent:         'my-agent',      // agent name in NotiLens
  token:         'YOUR_TOKEN',    // NotiLens topic token
  secret:        'YOUR_SECRET',   // NotiLens topic secret
  task:          'rag-pipeline',  // fixed task label (default: chain class name)
  loopThreshold:   10,            // agent steps before loop alert fires (default: 10)
  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

You can set custom metrics or fire custom events on the active run directly from the handler:

```ts
// 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' });
handler.track('custom.event', 'Something happened', { level: 'info', meta: { key: 'value' } });
```

> **Note:** Calling `metric()` or `track()` 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

```ts
import { NotiLens } from '@notilens/notilens';
import { NotiLensCallbackHandler } from '@notilens/langchain';

const nl = NotiLens.init('my-agent', { token: '...', secret: '...' });
const handler = new NotiLensCallbackHandler({ nlAgent: nl });
```

## Environment variables

```bash
export NOTILENS_TOKEN="your_token"
export NOTILENS_SECRET="your_secret"
```

```ts
// Token and secret picked up automatically
const handler = new NotiLensCallbackHandler({ agent: 'my-agent' });
```