---
title: "Add Caveman observations to LangGraph.js"
description: "This path adds observations to an existing JavaScript LangGraph application. It does not migrate graph execution, and it does not apply to Python LangGraph."
canonical: https://caveman.so/switch/langgraph
last-updated: 2026-09-07
---

# Add Caveman observations to LangGraph.js

This path adds observations to an existing JavaScript LangGraph application. It does not migrate graph execution, and it does not apply to Python LangGraph.

Use Node 22.19 or newer, `@langchain/langgraph@1.4.13`, and `@langchain/core@1.2.9` for the reviewed adapter. Build the Caveman source workspace through [the SDK setup guide](/guides/agent-sdk-migration). The adapter is experimental and uncertified; the older published npm SDK does not supply the documented source API.

## Save the graph's execution contract

Record nodes, edges, state schema, checkpointer configuration, thread identifiers, interrupt behavior, model clients, and tool side effects. Preserve existing callbacks and stream transformers.

Choose a staging task that invokes a tool, pauses, and resumes. Add a failed model or tool case. Use disposable resources for any operation with side effects.

Keep the graph and dependency versions fixed during the observation trial. Review [LangGraph's runtime documentation](https://docs.langchain.com/oss/javascript/langgraph/overview) for your existing execution behavior.

## Compose the native hooks

The following is an integration excerpt. `builder`, `checkpointer`, `existingTransformers`, `existingCallbacks`, `input`, and the two logs belong to your current application. Supply the actual model identity used by a single-model graph:

```ts
import { createLangGraphAdapter } from "@caveman-ai/adapter-langgraph";

const cave = createLangGraphAdapter({
  model: modelIdentity,
  onLifecycle: event => lifecycleLog.push(event),
  onUsage: ({ usage, identity }) => {
    usageLog.push({ usage, identity });
  },
});

const graph = builder.compile({
  checkpointer,
  transformers: cave.composeTransformers(existingTransformers),
});

const result = await graph.invoke(input, cave.composeConfig({
  callbacks: existingCallbacks,
  configurable: { thread_id: "migration-test-1" },
}));
```

`modelIdentity` has `provider` and `model` string fields. For a graph that uses several models, implement the adapter's documented identity resolver instead of assigning every call one static model. See [the source API](https://github.com/caveman-ai/agent-sdk/tree/main/packages/adapters/langgraph).

Use composition helpers to retain native callbacks and transformers. Do not replace the production callback array with a new array that only contains Caveman.

## Confirm what the adapter observes

Compare lifecycle and usage observations with the native run. Check that model and tool calls attach to the correct task, and that a resumed task remains distinguishable from a new attempt.

Usage comes from native `AIMessage.usage_metadata`. Missing cache, reasoning, or total evidence remains unknown. Incomplete cache details can prevent input from being represented as a disjoint count. Do not fill those gaps with zeros in your logging sink.

The adapter is observation-only. It cannot mutate context, enforce a budget, change models, or own retries. Tracing, durable observation, replay awareness, and compilation are unsupported.

## Test native behavior under failure

Exercise a provider error, failed tool, interrupted run, resume, and stream cancellation. Compare the direct and instrumented result or error. Make the observation sink throw in staging and confirm native execution remains intact.

Inspect callback return values and side effects as well as the final answer. A hook that still runs but runs twice is a regression.

## Evaluate optimization separately

If the records reveal repeated expensive context, select a supported compression path or an application change. Keep graph execution fixed and test the candidate against the saved tasks.

The LangGraph adapter's presence does not mean compression occurred. Count full-task provider usage and verify the final artifact with [the evaluation method](/guides/agent-evaluations).

## Roll back

Restore the original callbacks and transformers, leaving graph code and checkpoint storage unchanged. Confirm a saved task resumes through the direct configuration. Preserve observation records needed to explain the trial.

For a full move to Caveman's own agent runtime, map checkpoints, interrupts, tools, and state individually before rewriting. The [comparison](/compare/langgraph) explains why that is a larger decision than adding observations.
