You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 6350513
Browse filesBrowse the repository at this point in the historyBrowse files
feat(temporal): opt-in continue-as-new for long-lived agent workflows
Long-lived chat/session agents run as a single Temporal workflow that stays open
indefinitely. Two things killed them: event history grows past Temporal's
~50k-event / 50MB limit, and the 24h execution-timeout default terminated the
whole chain. This adds an opt-in continue-as-new pattern on BaseWorkflow and
defaults the execution timeout to infinite.
Opt-in by adoption: an agent gets recycling only by calling run_until_complete
from its @workflow.run instead of a bare wait_condition(timeout=None). No flag,
no patch gate (no in-flight long-running workflows to preserve; Worker Versioning
+ upgrade-on-continue-as-new is the path for evolving these later).
BaseWorkflow helpers:
- run_until_complete(*args, is_complete, timeout=None): keep the workflow open;
recycle history when Temporal suggests it.
- should_continue_as_new(): recycle when workflow.info().is_continue_as_new_suggested().
- drain_and_continue_as_new(): drain all_handlers_finished and re-check completion
before workflow.continue_as_new.
Execution timeout: WORKFLOW_EXECUTION_TIMEOUT_SECONDS now defaults to None (no
execution timeout; None/0/negative -> execution_timeout=None). It is chain-wide
(continue-as-new does not reset it), so leaving it unset is required for a
forever-chat. Idle bounding is a durable timer (run_until_complete's timeout).
State restoration after a recycle is framework-specific and left to follow-up
PRs, one per integration. 000_hello_acp adopts the pattern (no cross-turn state,
so no rehydration needed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# 2. Wait for the task to be completed indefinitely. If we don't do this the workflow will close as soon as this function returns. Temporal can run hundreds of millions of workflows in parallel, so you don't need to worry about too many workflows running at once.
66
-
67
-
# Thus, if you want this agent to field events indefinitely (or for a long time) you need to wait for a condition to be met.
68
-
awaitworkflow.wait_condition(
69
-
lambda: self._complete_task,
70
-
timeout=None, # Set a timeout if you want to prevent the task from running indefinitely. Generally this is not needed. Temporal can run hundreds of millions of workflows in parallel and more. Only do this if you have a specific reason to do so.
71
-
)
65
+
# 2. Keep the workflow open to field events. We use run_until_complete
66
+
# instead of a bare wait_condition: it still waits indefinitely, but also
67
+
# recycles the Temporal event history via continue-as-new before it hits the
68
+
# ~50k-event / 50MB limit, so this chat can stay open forever. Adopting
69
+
# run_until_complete IS the opt-in — agents that keep the old wait_condition
70
+
# never recycle. This agent keeps no cross-turn state, so nothing needs
71
+
# restoring across a recycle and `params` is the only carry-forward. (Agents
72
+
# that DO keep state restore it at the top of @workflow.run on a recycled
73
+
# run — framework-specific, landing per-integration in follow-up PRs.)
0 commit comments