Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/wayflowcore/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@
'Cannot handle as a local function: "wayflowcore.agentspec.components.nodes.ExtendedLlmNode.check_either_prompt_str_or_object_is_used" (use @functools.wraps)',
"py:class reference target not found: wayflowcore.mcp.mcphelpers.ToolOutuptTypeT",
"py:class reference target not found: wayflowcore.mcp.mcphelpers.ContextType",
(
'Cannot resolve forward reference in type annotations of "wayflowcore.agentserver.serverstorageconfig.ServerStorageConfig": '
"name 'Datastore' is not defined"
),
]


Expand Down Expand Up @@ -256,6 +260,13 @@ def filter(self, record):
("py:class", r"wayflowcore.executors._events.event.Event"),
("py:class", r"(?:wayflowcore\.executors\._executor\.)?ConversationExecutor"),
("py:class", r"(?:wayflowcore\.executors\._executionstate\.)?ConversationExecutionState"),
("py:class", r"(?:wayflowcore\.executors\._agentconversation\.)?AgentConversation"),
("py:class", r"(?:wayflowcore\.executors\._flowconversation\.)?FlowConversation"),
("py:class", r"(?:wayflowcore\.executors\._a2aagentconversation\.)?A2AAgentConversation"),
(
"py:class",
r"(?:wayflowcore\.executors\._managerworkersconversation\.)?ManagerWorkersConversation",
),
("py:class", r"wayflowcore.executors._agentexecutor.AgentConversationExecutionState"),
("py:class", r"wayflowcore.executors._flowexecutor.FlowConversationExecutionState"),
("py:class", r"wayflowcore.agentserver.a2a._app.A2AApp"),
Expand Down
34 changes: 34 additions & 0 deletions docs/wayflowcore/source/core/api/checkpointing.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.. _checkpointing:

Checkpointing
=============

Checkpointing APIs persist and restore conversation state across process restarts,
debugging sessions, and server requests.

Core types
----------

.. autoclass:: wayflowcore.checkpointing.ConversationCheckpoint

.. autoclass:: wayflowcore.checkpointing.CheckpointingInterval

.. autoclass:: wayflowcore.checkpointing.Checkpointer
:members: load_latest, load, save, save_async, list_checkpoints, delete

Storage configuration
---------------------

.. autoclass:: wayflowcore.checkpointing.StorageConfig
:members: to_schema

Datastore-backed checkpointers
------------------------------

.. autoclass:: wayflowcore.checkpointing.DatastoreCheckpointer

.. autoclass:: wayflowcore.checkpointing.InMemoryCheckpointer

.. autoclass:: wayflowcore.checkpointing.PostgresCheckpointer

.. autoclass:: wayflowcore.checkpointing.OracleDatabaseCheckpointer
1 change: 1 addition & 0 deletions docs/wayflowcore/source/core/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ API Reference
:maxdepth: 3

Agent Spec Adapters <agentspec>
Checkpointing <checkpointing>
Conversations <conversation>
LLMs <llmmodels>
Events <events>
Expand Down
19 changes: 16 additions & 3 deletions docs/wayflowcore/source/core/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ Changelog
WayFlow |current_version|
-------------------------

New features
^^^^^^^^^^^^

* **First-class conversation checkpointing**

Added shared conversation checkpointing for Agents, Flows, Swarms, ManagerWorkers, and A2A agents through
``ConversationCheckpoint``, ``Checkpointer``, ``InMemoryCheckpointer``, ``PostgresCheckpointer``, and
``OracleDatabaseCheckpointer``. Conversations can now resume from ``conversation_id``, load specific checkpoints for
time-travel debugging, and choose checkpoint save frequency with ``CheckpointingInterval``.

The OpenAI Responses server path now uses this shared checkpointing subsystem as well, so persisted
``previous_response_id`` and ``conversation`` behavior is handled through the same checkpoint model.

For more information, see :doc:`how to checkpoint and resume conversations <howtoguides/howto_checkpointing>`
and the :doc:`API reference on checkpointing <api/checkpointing>`.

Improvements
^^^^^^^^^^^^

Expand Down Expand Up @@ -87,15 +103,12 @@ New features
For more information read the :doc:`API Reference on LLM models <api/llmmodels>` and the guide on
:doc:`how to use LLMs from different providers <howtoguides/llm_from_different_providers>`.


* **Logprob support in `LlmGenerationConfig` and `PromptExecutionStep`**

Add per-token log-probabilities support with the ``top_logprobs`` generation config parameter and support returning
per-token log-probabilities in the ``PromptExecutionStep``.
For more information please read the guide on :ref:`How to request per-token log-probabilities <request_logprobs>`



Improvements
^^^^^^^^^^^^

Expand Down
71 changes: 71 additions & 0 deletions docs/wayflowcore/source/core/code_examples/howto_checkpointing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright © 2026 Oracle and/or its affiliates.
#
# This software is under the Apache License 2.0
# (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License
# (UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option.

# isort:skip_file
# fmt: off
# mypy: ignore-errors
# docs-title: Code Example - How to Checkpoint and Resume Conversations

# .. start-##_Configure_your_LLM
from wayflowcore.models import VllmModel

llm = VllmModel(
model_id="LLAMA_MODEL_ID",
host_port="LLAMA_API_URL",
)
# .. end-##_Configure_your_LLM

llm: VllmModel # docs-skiprow
(llm,) = _update_globals(["llm_small"]) # docs-skiprow # type: ignore

# .. start-##_Start_a_checkpointed_conversation
from wayflowcore import Agent
from wayflowcore.checkpointing import InMemoryCheckpointer

agent = Agent(llm=llm)
checkpointer = InMemoryCheckpointer()
conversation_id = "support-conversation-1"

conversation = agent.start_conversation(
conversation_id=conversation_id,
checkpointer=checkpointer,
)

status = conversation.execute()
# .. end-##_Start_a_checkpointed_conversation

# .. start-##_Resume_the_latest_checkpoint
restored_conversation = agent.start_conversation(
conversation_id=conversation_id,
checkpointer=checkpointer,
)

restored_conversation.append_user_message("Continue from where you left off.")
status = restored_conversation.execute()
# .. end-##_Resume_the_latest_checkpoint

# .. start-##_Load_a_specific_checkpoint
# Checkpoints are ordered oldest -> newest.
checkpoints = checkpointer.list_checkpoints(conversation_id)

previous_checkpoint = checkpoints[-2]
rewound_conversation = agent.start_conversation(
conversation_id=conversation_id,
checkpoint_id=previous_checkpoint.checkpoint_id,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better for start_conversation to take a checkpoint object rather than a checkpoint_id ?

checkpointer=checkpointer,
)

rewound_conversation.append_user_message("Try a different path from here.")
status = rewound_conversation.execute()
# .. end-##_Load_a_specific_checkpoint

# .. start-##_Control_checkpoint_frequency
from wayflowcore.checkpointing import CheckpointingInterval, InMemoryCheckpointer

checkpointer = InMemoryCheckpointer(
checkpointing_interval=CheckpointingInterval.ALL_INTERNAL_TURNS,
)
# .. end-##_Control_checkpoint_frequency
151 changes: 151 additions & 0 deletions docs/wayflowcore/source/core/howtoguides/howto_checkpointing.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
.. _top-howtocheckpointing:

==========================================
How to Checkpoint and Resume Conversations
==========================================

.. admonition:: Prerequisites

This guide assumes familiarity with:

- :doc:`Agents <../tutorials/basic_agent>`
- :doc:`Flows <../tutorials/basic_flow>`
- :doc:`Serve Agents with WayFlow <howto_serve_agents>`

Checkpointing lets WayFlow save a conversation while it runs and load it again later using the
same ``conversation_id``. Use it when you want to:

- continue after a process restart
- pause a long-running workflow and come back to it later
- inspect earlier checkpoints while debugging
- retry from an older checkpoint with different code or inputs


Choose a checkpointer
=====================

The checkpointer is the object that reads and writes checkpoints. WayFlow includes:

- ``InMemoryCheckpointer`` for tests and local experimentation
- ``PostgresCheckpointer`` for PostgreSQL-backed persistence
- ``OracleDatabaseCheckpointer`` for Oracle-backed persistence

All checkpointers use the same methods for loading, listing, and deleting checkpoints.
WayFlow saves checkpoints automatically during conversation execution.


Start a checkpointed conversation
=================================

Attach a checkpointer when you start the conversation. The ``conversation_id`` is the name WayFlow
uses to find that conversation again.

.. literalinclude:: ../code_examples/howto_checkpointing.py
:language: python
:start-after: .. start-##_Start_a_checkpointed_conversation
:end-before: .. end-##_Start_a_checkpointed_conversation

Once checkpointing is enabled, WayFlow saves the top-level conversation automatically at the
configured checkpoints. If an Agent or Flow starts child conversations internally, WayFlow keeps
them attached to the same saved conversation. Application code only needs to pass the public
``conversation_id`` shown above.

For checkpointing, there are three useful identifiers:

- ``conversation_id``: the durable conversation id used to resume and list checkpoints
- ``checkpoint_id``: the exact saved snapshot to reload
- ``conversation.id``: the id of one concrete ``Conversation`` within that conversation thread

Each nested conversation gets its own ``conversation.id`` while inheriting the conversation thread's
``conversation_id``. Application code only supplies ``conversation_id``; child identities are
created and restored internally.

.. warning::

Checkpoints contain the serialized conversation, including messages and intermediate state.
Treat checkpoint storage like other persisted user conversation data: protect access, choose an
appropriate retention policy, and avoid storing it in places meant only for test data.


Resume the latest checkpoint
============================

To resume a conversation, call ``start_conversation()`` again with the same ``conversation_id`` and
checkpointer.

.. literalinclude:: ../code_examples/howto_checkpointing.py
:language: python
:start-after: .. start-##_Resume_the_latest_checkpoint
:end-before: .. end-##_Resume_the_latest_checkpoint

If the checkpointer has no saved state for that id, WayFlow starts a new conversation.


Load a specific checkpoint
==========================

You can also load an older checkpoint. This is useful when you want to replay part of a run or
compare what happens after changing a prompt, tool, or step.

.. literalinclude:: ../code_examples/howto_checkpointing.py
:language: python
:start-after: .. start-##_Load_a_specific_checkpoint
:end-before: .. end-##_Load_a_specific_checkpoint

``list_checkpoints()`` returns checkpoints ordered from oldest to newest, with the checkpoint id,
creation time, and metadata recorded when the checkpoint was saved. That means ``checkpoints[-1]``
is the newest checkpoint and ``checkpoints[-2]`` is the one before it.


Control checkpoint frequency
============================

Use ``CheckpointingInterval`` to choose how often WayFlow should save state.

.. literalinclude:: ../code_examples/howto_checkpointing.py
:language: python
:start-after: .. start-##_Control_checkpoint_frequency
:end-before: .. end-##_Control_checkpoint_frequency

The available options are:

- ``CONVERSATION_TURNS``: save after the main ``conversation.execute()`` call returns
- ``LLM_TURNS``: also save after internal turns that used an LLM
- ``ALL_INTERNAL_TURNS``: also save after each internal Agent or Flow turn

Saving more often gives WayFlow a more recent place to resume from, but it also writes more rows to
the checkpoint store.

WayFlow resumes from the last checkpoint it saved. It does not resume from the middle of a tool
call, LLM request, or step. If a crash happens after that checkpoint, code that ran after the
checkpoint may run again. Tools and steps with side effects should therefore be safe to retry. For
example, if a step writes to another service, sends a notification, or charges a payment method,
use your own idempotency key or tracking table so the side effect is not repeated.

When multiple processes share a relational checkpoint store, use a single writer per
``conversation_id``. WayFlow updates the "latest checkpoint" marker in one transaction for normal
writes, but the table does not enforce uniqueness for that marker. If two writers save the same
conversation at the same time, the store can end up with more than one checkpoint marked as latest.
In that case, loading by ``conversation_id`` raises an error instead of choosing one at random.
When recovering that history, load a specific ``checkpoint_id``.


Use checkpointing with the OpenAI Responses server
==================================================

The OpenAI Responses server uses the same checkpointing storage behind ``ServerStorageConfig``.
Existing OpenAI-compatible features such as ``previous_response_id``, ``conversation``,
``get_response()``, ``delete_response()``, and ``store=False`` continue to work through that shared
storage path.

If you are serving agents, configure storage the same way as in
:doc:`Serve Agents with WayFlow <howto_serve_agents>`. The server creates and uses the matching
checkpointer internally.


Next steps
==========

- :doc:`Serialize and Deserialize Conversations <howto_serialize_conversations>`
- :doc:`Serve Agents with WayFlow <howto_serve_agents>`
- :doc:`Build a Swarm of Agents <howto_swarm>`
1 change: 1 addition & 0 deletions docs/wayflowcore/source/core/howtoguides/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ These guides demonstrate how to configure the components of assistants built wit
:maxdepth: 1

Load and Execute an Agent Spec Configuration <howto_execute_agentspec_with_wayflowcore>
Checkpoint and Resume Conversations <howto_checkpointing>
Serialize and Deserialize Flows and Agents <howto_serdeser>
Serialize and Deserialize Conversations <howto_serialize_conversations>
Build a New WayFlow Component <howto_plugins>
Expand Down
2 changes: 2 additions & 0 deletions wayflowcore/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ filterwarnings =
# User Warning
# oci genai models requires an explicit number of max_tokens
ignore:Setting `max_tokens`:UserWarning
# In-memory storage is intentionally used by checkpointing integration tests.
ignore:InMemoryDatastore is for DEVELOPMENT and PROOF-OF-CONCEPT ONLY!:UserWarning
# tests for interrupts
ignore:The assistant is being executed without a time limit!:UserWarning
ignore:Usage of non-encrypted requests to http urls is considered unsecure and strongly discouraged:UserWarning
Expand Down
Loading