# LangChain (JavaScript)

Install Brizz alongside LangChain JS and add session tracking.

Quickstart for the LangChain JS integration shown during onboarding. For the full TypeScript SDK reference, see the [TypeScript SDK guide](/docs/sdks/typescript.md).

## Install

:::tabs
:::tab[npm]
```bash
npm install @brizz/sdk @langchain/core
```
:::tab[yarn]
```bash
yarn add @brizz/sdk @langchain/core
```
:::tab[pnpm]
```bash
pnpm add @brizz/sdk @langchain/core
```
:::

`@langchain/core` is an optional peer dependency of `@brizz/sdk` — install it alongside Brizz whenever you use LangChain so Brizz and LangChain share a single instance and callbacks flow correctly. The OpenInference LangChain instrumentation ships with `@brizz/sdk`, so you don't need to install it separately.

## Initialize

Pass LangChain's callback manager module so Brizz can wire in the OpenInference tracer.

```typescript
import * as CallbackManagerModule from "@langchain/core/callbacks/manager";
import { Brizz } from "@brizz/sdk";

Brizz.initialize({
  apiKey: process.env.BRIZZ_API_KEY,
  appName: process.env.BRIZZ_APP_NAME || "my-app",
  environment: process.env.NODE_ENV || "development",
  instrumentModules: {
    langchain: {
      callbackManagerModule: CallbackManagerModule,
    },
  },
});
```

## Sessions

Wrap your agent calls with `withSessionId` (and `withProperties` for user/account context).

```typescript
import { withSessionId, withProperties } from "@brizz/sdk";
import { HumanMessage } from "@langchain/core/messages";

// `agent` is your existing LangChain agent (createReactAgent, AgentExecutor, etc.).
async function callLLM(userMessage: string) {
  const output = await agent.invoke({
    messages: [new HumanMessage(userMessage)],
  });
  return output;
}

const sessionId = "unique-session-id";
const properties = {
  userId: "user-1234",
  accountId: "account-5678",
};

const wrappedCall = withProperties(
  properties,
  withSessionId(sessionId, callLLM),
);

await wrappedCall("Hello, how are you?");
```

### Alternative — no `withSessionId`, use LangChain metadata

If wrapping your call site with `withSessionId` is awkward (already-existing thread/conversation IDs, helper functions invoked from many places), pass the session identifier in LangChain's per-call `config.metadata` instead. Brizz reads it from the OpenInference span attribute and writes `brizz.session.id` for you — same conversation grouping, no SDK wrapper needed.

```typescript
import { HumanMessage } from "@langchain/core/messages";

// `llm` is your existing LangChain chat model (ChatOpenAI, ChatAnthropic, etc.).
await llm.invoke([new HumanMessage("Hello")], {
  metadata: { thread_id: "chat-session-123" },
});
```

Recognized keys, in priority order: `thread_id` → `session_id` → `conversation_id`. The first non-empty string wins.

Precedence: a Brizz `withSessionId` / `start_session` wrapper, or a standard OTel `session.id` attribute, still win over the metadata fallback when both are present.

## Dropping spans per end-user

Anything you put in `config.metadata` shows up on the OpenInference span as a JSON-stringified `metadata` attribute. You can read it from `beforeSendSpan` to drop telemetry for specific end-users — internal staff, test traffic, opted-out tenants:

```typescript
Brizz.initialize({
  apiKey: process.env.BRIZZ_API_KEY,
  instrumentModules: { langchain: { callbackManagerModule: CallbackManagerModule } },
  beforeSendSpan: (span) => {
    const raw = span.attributes['metadata'];
    if (typeof raw !== 'string') return true;
    try {
      return JSON.parse(raw).customer_id !== 'cust_42';
    } catch {
      return true;
    }
  },
});

await llm.invoke([new HumanMessage('Hello')], {
  metadata: { customer_id: 'cust_42' },
});
```

See the [TypeScript SDK guide](/docs/sdks/typescript.md#dropping-spans) for the full reference.

## Complete example

A single file you can copy, set `BRIZZ_API_KEY` + `OPENAI_API_KEY`, and run with `node agent.mjs`.

```typescript
// agent.ts
import * as CallbackManagerModule from '@langchain/core/callbacks/manager';
import { Brizz, withSessionId, withProperties, emitEvent } from '@brizz/sdk';
import { HumanMessage } from '@langchain/core/messages';
import { ChatOpenAI } from '@langchain/openai';

// callbackManagerModule MUST be the wildcard import — Brizz wires the
// OpenInference tracer through it. @langchain/core is a peer dep;
// install it alongside @brizz/sdk.
Brizz.initialize({
  apiKey: process.env.BRIZZ_API_KEY!,
  appName: 'my-app',
  environment: process.env.NODE_ENV ?? 'development',
  instrumentModules: { langchain: { callbackManagerModule: CallbackManagerModule } },
});

const llm = new ChatOpenAI({ model: 'gpt-4o-mini' });

async function callLLM(userMessage: string) {
  const out = await llm.invoke([new HumanMessage(userMessage)]);
  // User feedback — map "feedback.positive" / "feedback.negative" to system
  // events in Org Settings -> Event so it powers filters and the Overview chart.
  emitEvent(
    'feedback.positive',
    { category: 'helpfulness' },
    { comment: 'Exactly what I needed!', context: 'support-agent' },
  );
  return out.content;
}

// Option A — wrap your function with withSessionId + withProperties.
const wrapped = withProperties(
  { userId: 'user-42', accountId: 'acct-100' },
  withSessionId('chat-session-123', callLLM),
);
console.log(await wrapped('Hello!'));

// Option B — pass thread_id (or session_id / conversation_id) via LangChain
// metadata; Brizz reads it and groups calls under the same session.
const directReply = await llm.invoke(
  [new HumanMessage('Hello!')],
  { metadata: { thread_id: 'chat-session-123', customer_id: 'cust_42' } },
);
console.log(directReply.content);
```

**Gotchas**

- Install `@langchain/core` alongside `@brizz/sdk` — it's a peer dep.
- `callbackManagerModule` must be the wildcard `import * as ...`, not a default import.
- Anything in `config.metadata` becomes a JSON-stringified `metadata` span attribute — readable from `beforeSendSpan` (see [Dropping spans per end-user](#dropping-spans-per-end-user)).
- Recognized session keys (priority order): `thread_id` → `session_id` → `conversation_id`.

## See also

- [Node.js / TypeScript SDK](/docs/sdks/typescript.md) — the underlying SDK and full configuration.
- [Sessions](/docs/instrument/sessions.md) — session capture patterns.
- [Custom events](/docs/instrument/custom-events.md) — emit business events from LangChain flows.
