Skip to content

feat(workflows): declare retry on workflow tools - #207

Merged
Tsuyoshi Ushio (TsuyoshiUshio) merged 3 commits into
mainfrom
tsuyoshiushio-durable-activity-retry
Sep 10, 2026
Merged

Tsuyoshi Ushio (TsuyoshiUshio) merged 3 commits into
mainfrom
tsuyoshiushio-durable-activity-retry

Conversation

@TsuyoshiUshio

Copy link
Copy Markdown
Contributor

Summary

Complete the residual @workflow_tool(retry=...) integration left after #193 extracted and merged the plan-authored Durable retry execution foundation.

  • Adds a typed retry declaration to @workflow_tool and public retry policy exports.
  • Carries retry metadata through discovery and immutable handler/policy catalogs.
  • Makes a tool declaration authoritative over plan-authored execution.retry at submission.
  • Persists only the effective policy, preserving Extract plan-authored Durable retry execution #193's replay-safe execution contract.
  • Updates the retry sample to keep retryability with the tool author rather than the model-authored plan.

This intentionally replaces rather than rebases #185. That branch predates #193 and rebasing its full tree would reintroduce already-merged foundation work and materially enlarge the review diff.

Scope

No engine, Activity envelope, native retry driver, dependency, frontmatter schema, or UI changes. Those execution pieces are already in #193.

Validation

  • python -m ruff check src tests
  • python -m mypy src
  • python -m pytest --cache-clear --cov=./src/azure_functions_agents --cov-report=xml --cov-branch tests — 1183 passed, 55 deselected
  • python -m pytest -q -m e2e tests/endtoend/test_workflow_native_retry_e2e.py — 2 passed against a real Functions host and Docker Azurite

The real-host run used samples/workflow-retry-policy with local.settings.json copied from the #193 worktree and TASKHUB_NAME removed, so Durable used the default TaskHub.

Carry tool-owned retry metadata through discovery and immutable workflow policy catalogs, with decorator declarations overriding plan-authored retry at submission.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1d5e6bb1-d7be-4d68-bad7-cb3f80079d27
Keep explicit null execution values through submission validation and make the retry E2E build its payload through the production policy path.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1d5e6bb1-d7be-4d68-bad7-cb3f80079d27
Move workflow retry policy freezing out of frozen dataclass post-initialization and into the schema normalization boundary.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1d5e6bb1-d7be-4d68-bad7-cb3f80079d27
Comment thread samples/workflow-retry-policy/src/main.agent.md
@TsuyoshiUshio
Tsuyoshi Ushio (TsuyoshiUshio) merged commit 3ab9e8d into main Sep 10, 2026
16 checks passed
hallvictoria pushed a commit to danfiedler-msft/azure-functions-agents-runtime that referenced this pull request Sep 24, 2026
The retry foundation this slice depended on landed through PRs Azure#193 and Azure#207
rather than through the stale PR Azure#186 branch, whose versions of `schema.py`,
`activity.py`, and `engine.py` now conflict with the shipped contracts
wholesale. Record the remaining timeout and continue-on-error slice as a clean
reimplementation against current `main` instead of a rebase.

The design makes all three `execution` fields optional so a deadline can be
declared alone, resolves `@workflow_tool` precedence per field, bounds one
attempt at the Activity boundary under a new retryable `timeout`
classification, and lets a declared-continuation node commit a bounded
controlled-failure result so its dependents run.

Fail-fast is preserved for everything that cannot be continued: the wave
selection loop keeps awaiting only when the completed instance both declared
continuation and failed continuably, so a non-continuable failure never waits
behind a slow sibling or a long timer. Both persisted keys are written only
when authored, so a task that declares neither freezes and replays the payload
the retry-only runtime wrote.

An independent architecture review raised four blocking findings — whole-wave
collection, unaddressed downgrade, an underspecified continuation contract, and
missing coverage of mixed waves, cancellation races, and `for_each` failure
shapes. Decisions 88 and 92-96 and the expanded test plan resolve them.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f32b40a3-603f-48d9-ad29-43179afe265b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants