Principle:Langchain ai Langgraph Entrypoint Configuration
| Attribute | Value |
|---|---|
| Concept | Configuring entrypoint persistence with split return values and checkpoint state |
| Workflow | Functional_API_Workflow |
| Type | Principle |
| Repository | Langchain_ai_Langgraph |
| Source | libs/langgraph/langgraph/func/__init__.py
|
Overview
When an @entrypoint is configured with a checkpointer, its return value is persisted as the checkpoint state for the current thread. On subsequent invocations with the same thread ID, this persisted value is made available through the previous injectable parameter. The entrypoint.final pattern extends this by allowing the developer to decouple the value returned to the caller from the value saved to the checkpoint, enabling workflows where the external API response differs from the internal persisted state.
This principle covers the interplay between entrypoint configuration parameters (checkpointer, store, cache, policies), the previous parameter for accessing prior checkpoint state, and the entrypoint.final dataclass for split return/save semantics.
Description
Checkpoint Value Separation
By default, when an entrypoint returns a value and a checkpointer is active, the same value serves two purposes:
- It is returned to the caller as the workflow result.
- It is saved to the checkpoint and becomes the
previousvalue on the next invocation.
This works well for simple cases, but many real workflows need different values for these two purposes. For example:
- A workflow might return a summary to the user while saving the full processing history to the checkpoint.
- A running counter might return the current accumulated value while saving the new accumulated value.
- A workflow might return a formatted response while saving raw structured data for future processing.
The entrypoint.final dataclass solves this by providing two distinct fields: value (what the caller receives) and save (what gets checkpointed).
The previous Parameter
When a checkpointer is provided to the entrypoint decorator, the decorated function can declare a previous keyword parameter:
@entrypoint(checkpointer=InMemorySaver())
def my_workflow(input_data: str, *, previous: str | None = None) -> str:
# previous contains the saved value from the last invocation on this thread
...
The previous parameter is automatically injected by the runtime. Its value is:
None(or the declared default) on the first invocation for a given thread.- The return value of the previous invocation, or the
savefield ofentrypoint.finalif that was used.
This mechanism enables stateful workflows that accumulate information across multiple invocations without requiring the caller to manage state externally.
The entrypoint.final Pattern
The entrypoint.final[R, S] dataclass is a generic type with two type parameters:
R: The type of the value returned to the caller.S: The type of the value saved to the checkpoint.
When the entrypoint function's return type annotation includes entrypoint.final, the runtime's internal mappers (_pluck_return_value and _pluck_save_value) extract the appropriate field from the returned object:
- The
valuefield is written to theENDchannel (returned to the caller). - The
savefield is written to thePREVIOUSchannel (persisted in the checkpoint).
If the function returns a plain value (not an entrypoint.final instance), both channels receive the same value, preserving backward compatibility.
Entrypoint Configuration Parameters
The entrypoint decorator's __init__ accepts several configuration parameters that control persistence and resilience:
- checkpointer: A
BaseCheckpointSaverinstance that enables state persistence. Without a checkpointer, thepreviousparameter is unavailable and interrupts cannot be resumed. Common implementations includeInMemorySaver(for development) andPostgresSaver(for production).
- store: A
BaseStoreinstance providing a general-purpose key-value store. Unlike the checkpointer (which is scoped to threads), the store enables cross-thread and cross-workflow data sharing. Accessible via theruntimeinjectable parameter.
- cache: A
BaseCacheinstance for caching workflow and task results. When combined with acache_policy, enables memoization at the workflow level.
- cache_policy: A
CachePolicycontrolling how cache keys are generated and when cached entries expire (via TTL).
- retry_policy: A
RetryPolicyor sequence of policies controlling automatic retry behavior for the entire workflow in case of failure.
- context_schema: A type that defines the schema for runtime context objects, enabling typed access to static configuration passed at invocation time.
Usage
from typing import Any
from langgraph.func import entrypoint
from langgraph.checkpoint.memory import InMemorySaver
# Simple persistence: return value IS the saved value
@entrypoint(checkpointer=InMemorySaver())
def counter(increment: int, *, previous: int | None = None) -> int:
current = (previous or 0) + increment
return current # Both returned and saved
config = {"configurable": {"thread_id": "counter-1"}}
counter.invoke(5, config) # Returns 5
counter.invoke(3, config) # Returns 8 (previous was 5)
counter.invoke(2, config) # Returns 10 (previous was 8)
# Split return/save: return value DIFFERS from saved value
@entrypoint(checkpointer=InMemorySaver())
def accumulator(
value: int,
*,
previous: Any = None,
) -> entrypoint.final[int, int]:
previous = previous or 0
# Return the previous accumulation, save the new one
return entrypoint.final(value=previous, save=previous + value)
config = {"configurable": {"thread_id": "acc-1"}}
accumulator.invoke(3, config) # Returns 0 (previous was None), saves 3
accumulator.invoke(7, config) # Returns 3 (previous was 3), saves 10
accumulator.invoke(5, config) # Returns 10 (previous was 10), saves 15
Theoretical Basis
The entrypoint configuration model draws from several foundational concepts:
- Event Sourcing and State Snapshots: The checkpoint system implements a form of state snapshotting where the workflow's output state is persisted after each invocation. The
previousparameter provides access to the last snapshot, similar to how event-sourced systems reconstruct state from stored events. Theentrypoint.finalpattern extends this by allowing the projection (returned to the caller) to differ from the persisted state (saved for future invocations).
- Continuation-Passing Style: The
previousparameter andentrypoint.finalpattern resemble continuation-passing style (CPS) in programming language theory. Each invocation receives the "continuation state" from the previous execution and produces both a result and a new continuation state. This enables stateful computation across discrete invocations without requiring an external state management layer.
- Read-Your-Writes Consistency: When a checkpointer is active, the system guarantees that the next invocation on the same thread sees exactly the value that was saved (or returned) by the previous invocation. This read-your-writes consistency model simplifies reasoning about multi-invocation workflows.
- Separation of Concerns: The
entrypoint.finalpattern embodies the principle that the external interface (what the caller sees) and the internal state (what the system persists) serve different purposes and should not be forced to use the same representation. This is analogous to the CQRS (Command Query Responsibility Segregation) pattern in distributed systems, where the read model and write model are deliberately separated.