@b4run/langgraph

Use this whenCopy link to section: Use this when

Use this package when a B4.run runtime or framework extension must normalize graph and workflow route modules or execute those entries through B4.run's backend-adapter contract. Route authors normally use the SDK route contracts and let the CLI choose these adapters.

Install and importCopy link to section: Install and import

bash
npm install @b4run/langgraph
ts
import { defineEntry, graphAdapter, normalizeRouteModule } from "@b4run/langgraph"
import type { RouteModule } from "@b4run/langgraph/route-module"

Use @b4run/langgraph/define-entry for the smallest entry-validation import and @b4run/langgraph/route-module for normalization contracts without the adapters.

Compatibility and audienceCopy link to section: Compatibility and audience

SurfaceRuntimePurityAudienceStability
@b4run/langgraphedge-safedependency-freeintegrationsupported
@b4run/langgraph/define-entryedge-safedependency-freeintegrationsupported
@b4run/langgraph/route-moduleedge-safedependency-freeintegrationsupported

All three runtime surfaces bundle without third-party runtime dependencies or Node globals. That covers importing and running these adapters. It says nothing about a graph, workflow, or tool your application supplies.

Public exportsCopy link to section: Public exports

@b4run/langgraphCopy link to section: @b4run/langgraph

ExportResponsibility
defineEntryValidate and return a graph-or-workflow route module unchanged.
graphAdapterExecute callable graphs or objects with invoke(input).
workflowAdapterExecute callable workflow entries.
GraphRouteModuleDescribe a module with a graph entry.
NormalizedRouteModuleDescribe the normalized kind, entry, and config.
normalizeRouteModuleValidate and normalize either route-module form.
RouteConfigRe-export the SDK-owned route configuration.
RouteKindRe-export the SDK-owned agent, chain, graph, or workflow kind.
RouteModuleUnite graph and workflow route-module forms.
WorkflowRouteModuleDescribe a module with a workflow entry.
RuntimeContextRe-export the SDK-owned runtime context.
RuntimeToolRe-export the SDK-owned callable tool contract.

ToolRegistry lives in a private implementation module and is not exported.

@b4run/langgraph/define-entryCopy link to section: @b4run/langgraph/define-entry

ExportResponsibility
defineEntryValidate and preserve one route-module object.

@b4run/langgraph/route-moduleCopy link to section: @b4run/langgraph/route-module

ExportResponsibility
GraphRouteModuleDescribe a module with a graph entry.
NormalizedRouteModuleDescribe the normalized kind, entry, and config.
normalizeRouteModuleProduce a normalized route module.
assertExactlyOneEntryAssert the runtime graph/workflow exclusivity rule.
RouteConfigRe-export the SDK-owned route configuration.
RouteKindRe-export the SDK-owned route kind.
RouteModuleUnite graph and workflow module forms.
WorkflowRouteModuleDescribe a module with a workflow entry.

The route-module subpath exposes only its published normalization and route-module contracts.

Key contractsCopy link to section: Key contracts

ts
export declare function defineEntry<TEntry, TModule extends RouteModule<TEntry>>(
  module: TModule,
): TModule
ts
export interface GraphRouteModule<TEntry = unknown> {
  readonly graph: TEntry
  readonly workflow?: never
  readonly config?: RouteConfig
}

Fields: @b4run/langgraph#./route-module:GraphRouteModule

FieldTypeRequiredDescription
readonly graphTEntryyesSupply the graph entry.
readonly workflownevernoExclude the workflow alternative.
readonly configRouteConfignoConfigure the route; normalization defaults it to {}.
ts
export interface WorkflowRouteModule<TEntry = unknown> {
  readonly workflow: TEntry
  readonly graph?: never
  readonly config?: RouteConfig
}

Fields: @b4run/langgraph#./route-module:WorkflowRouteModule

FieldTypeRequiredDescription
readonly workflowTEntryyesSupply the workflow entry.
readonly graphnevernoExclude the graph alternative.
readonly configRouteConfignoConfigure the route; normalization defaults it to {}.
ts
export type RouteModule<TEntry = unknown> = GraphRouteModule<TEntry>
  | WorkflowRouteModule<TEntry>
ts
export interface NormalizedRouteModule<TEntry = unknown> {
  readonly kind: RouteKind
  readonly entry: TEntry
  readonly config: RouteConfig
}

Fields: @b4run/langgraph#./route-module:NormalizedRouteModule

FieldTypeRequiredDescription
readonly kindRouteKindyesIdentify the selected route entry kind.
readonly entryTEntryyesHold the selected graph or workflow.
readonly configRouteConfigyesHold the supplied config or {}.
ts
export declare function normalizeRouteModule<TEntry>(
  module: RouteModule<TEntry> | (GraphRouteModule<TEntry> & WorkflowRouteModule<TEntry>),
): NormalizedRouteModule<TEntry>
ts
export declare function assertExactlyOneEntry<TEntry>(
  module: RouteModule<TEntry> | (GraphRouteModule<TEntry> & WorkflowRouteModule<TEntry>),
): asserts module is RouteModule<TEntry>

Behavior contractsCopy link to section: Behavior contracts

Behavior contract langgraph.entry.exclusive

A route module must provide exactly one of graph or workflow.

Entry validation caveats

An explicitly undefined key counts as absent. defineEntry() returns the original object, while normalizeRouteModule() fills an omitted config with a new empty object. Invalid modules throw synchronously before an entry executes.

Behavior contract langgraph.route-module.surface

The route-module subpath exposes only its published normalization and route-module contracts.

Adapter lifecycle and failures

graphAdapter calls a function directly or calls an object's invoke. workflowAdapter accepts only a function. Both pass { signal }, await the result, and implement stream() as a single yielded execute result, with no native multi-chunk graph streaming. The runtime, streaming, and tags route-config fields are reserved, and these adapters ignore them.

ts
import { defineEntry, normalizeRouteModule } from "@b4run/langgraph"
 
const route = defineEntry({
  workflow: async (input: { name: string }, { signal }: { signal: AbortSignal }) => {
    signal.throwIfAborted()
    return { greeting: `Hello, ${input.name}` }
  },
  config: { runtime: "node", streaming: false }, // reserved; no adapter runtime effect
})
 
const normalized = normalizeRouteModule(route)
console.log(normalized.kind) // workflow

Continue with Routes, SDK API, and CLI API.