new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

LangChain · LangGraph · all subjects

graph-api

133 notes in this subject, read out of this brain and free to use. This is page 3 of 3.

Accessing current step counter in nodes

The current step counter is accessible in config["metadata"]["langgraph_step"] (Python) or config.metadata.langgraph_step (JavaScript) within any node. LangGraph increments this counter as the graph executes. This allows for proactive recursion handling before hitting the recursion limit and enables implementing graceful degradation strategies within graph logic.

RemainingSteps managed value for proactive recursion handling

LangGraph provides a RemainingSteps managed value that automatically tracks how many steps remain before hitting the recursion limit. Add remaining_steps: RemainingSteps to a TypedDict State definition. RemainingSteps is automatically populated by LangGraph and allows checking remaining steps within nodes and conditional edges to implement graceful degradation. This enables returning partial results or routing to fallback nodes when approaching the limit without raising an exception.

Available metadata in config within nodes

Along with langgraph_step, the following metadata is available in config["metadata"] (Python) or config.metadata (JavaScript): langgraph_node (current node name), langgraph_triggers (what triggered the node), langgraph_path (path taken through graph), and langgraph_checkpoint_ns (checkpoint namespace).

Runtime context Python example

Example showing how to use runtime context in Python: ```python @dataclass class ContextSchema: llm_provider: str = "openai" graph = StateGraph(State, context_schema=ContextSchema) graph.invoke(inputs, context={"llm_provider": "anthropic"}) from langgraph.runtime import Runtime def node_a(state: State, runtime: Runtime[ContextSchema]): llm = get_llm(runtime.context.llm_provider) ```

Runtime context JavaScript example

Example showing how to use runtime context in JavaScript: ```typescript import { StateGraph, StateSchema } from "@langchain/langgraph"; import * as z from "zod"; const State = new StateSchema({ input: z.string(), output: z.string(), }); const ContextSchema = z.object({ llm: z.union([z.literal("openai"), z.literal("anthropic")]), }); const graph = new StateGraph(State, ContextSchema); const config = { context: { llm: "anthropic" } }; await graph.invoke(inputs, config); const nodeA: GraphNode<typeof State> = (state, config) => { const llm = getLLM(config.context?.llm); return {}; }; ```

Accessing current step counter example

Example showing how to access the current step counter in a Python node: ```python from langchain_core.runnables import RunnableConfig from langgraph.graph import StateGraph def my_node(state: dict, config: RunnableConfig) -> dict: current_step = config["metadata"]["langgraph_step"] print(f"Currently on step: {current_step}") return state ``` Example in JavaScript: ```typescript import { RunnableConfig } from "@langchain/core/runnables"; import { StateGraph } from "@langchain/langgraph"; const myNode: GraphNode<typeof State> = async (state, config) => { const currentStep = config.metadata?.langgraph_step; console.log(`Currently on step: ${currentStep}`); return state; } ```

Recursion limit configuration at runtime

The recursion_limit (Python) or recursionLimit (JavaScript) is configured at runtime via the config parameter passed to invoke or stream methods. In Python: graph.invoke(inputs, config={"recursion_limit": 5}, context={"llm": "anthropic"}). In JavaScript: await graph.invoke(inputs, { recursionLimit: 5, context: { llm: "anthropic" } }). The recursion limit key should not be nested inside the configurable key.

Proactive vs reactive recursion handling comparison table

Comparison table for Python approaches to handling recursion limits: | Approach | Detection | Handling | Control Flow | |----------|-----------|----------|---------------| | Proactive (using RemainingSteps) | Before limit reached | Inside graph via conditional routing | Graph continues to completion node | | Reactive (catching GraphRecursionError) | After limit exceeded | Outside graph in try/catch | Graph execution terminated | Proactive advantages: Graceful degradation within the graph, Can save intermediate state in checkpoints, Better user experience with partial results, Graph completes normally (no exception). Reactive advantages: Simpler implementation, No need to modify graph logic, Centralized error handling.

Proactive recursion handling complete Python example

Complete Python example of proactive approach using RemainingSteps: ```python from typing import Annotated, Literal, TypedDict from langgraph.graph import StateGraph, START, END from langgraph.managed import RemainingSteps from langgraph.errors import GraphRecursionError class State(TypedDict): messages: Annotated[list, lambda x, y: x + y] remaining_steps: RemainingSteps def agent_with_monitoring(state: State) -> dict: remaining = state["remaining_steps"] if remaining <= 2: return {"messages": ["Approaching limit, returning partial result"]} return {"messages": [f"Processing... ({remaining} steps remaining)"]} def route_decision(state: State) -> Literal["agent", END]: if state["remaining_steps"] <= 2: return END return "agent" builder = StateGraph(State) builder.add_node("agent", agent_with_monitoring) builder.add_edge(START, "agent") builder.add_conditional_edges("agent", route_decision) graph = builder.compile() result = graph.invoke({"messages": []}, {"recursion_limit": 10}) ```

Reactive recursion error handling Python example

Python example of reactive approach catching GraphRecursionError: ```python from langgraph.errors import GraphRecursionError try: result = graph.invoke({"messages": []}, {"recursion_limit": 10}) except GraphRecursionError as e: result = {"messages": ["Fallback: recursion limit exceeded"]} ```

Reactive recursion error handling JavaScript example

JavaScript example of reactive approach catching GraphRecursionError: ```typescript import { GraphRecursionError } from "@langchain/langgraph"; try { const result = await app.invoke( { messages: [] }, { recursionLimit: 10 } ); } catch (error) { if (error instanceof GraphRecursionError) { console.log("Recursion limit reached, handling gracefully"); } } ```

Inspecting metadata in nodes Python example

Python example showing how to inspect all available metadata in a node: ```python def inspect_metadata(state: dict, config: RunnableConfig) -> dict: metadata = config["metadata"] print(f"Step: {metadata['langgraph_step']}") print(f"Node: {metadata['langgraph_node']}") print(f"Triggers: {metadata['langgraph_triggers']}") print(f"Path: {metadata['langgraph_path']}") print(f"Checkpoint NS: {metadata['langgraph_checkpoint_ns']}") return state ```

Inspecting metadata in nodes JavaScript example

JavaScript example showing how to inspect all available metadata in a node: ```typescript const inspectMetadata: GraphNode<typeof State> = async (state, config) => { const metadata = config.metadata; console.log(`Step: ${metadata?.langgraph_step}`); console.log(`Node: ${metadata?.langgraph_node}`); console.log(`Triggers: ${metadata?.langgraph_triggers}`); console.log(`Path: ${metadata?.langgraph_path}`); console.log(`Checkpoint NS: ${metadata?.langgraph_checkpoint_ns}`); return state; } ```

Give your agent this brain