Skip to content

Add durability capabilities for Temporal, DBOS, and Prefect#4977

Draft
DouweM wants to merge 5 commits intomainfrom
temporal-durability-cap
Draft

Add durability capabilities for Temporal, DBOS, and Prefect#4977
DouweM wants to merge 5 commits intomainfrom
temporal-durability-cap

Conversation

@DouweM
Copy link
Copy Markdown
Collaborator

@DouweM DouweM commented Apr 4, 2026

Summary

  • TemporalDurability capability that routes model requests and tool execution through Temporal activities using capability hooks (wrap_model_request, wrap_run, get_wrapper_toolset) instead of requiring WrapperAgent/WrapperModel subclasses
  • DBOSDurability and PrefectDurability — TODO, in progress
  • DurabilityPlugin for Temporal worker activity registration
  • Shared RequestParams type (renamed from _RequestParams) for cross-module use
  • Fix ReplayStreamedResponse type narrowing for PartStartEvent.index

Test plan

  • 9 new tests for TemporalDurability (workflow integration, tool wrapping, passthrough, validation, model registry)
  • All 87 existing temporal tests pass
  • Add DBOSDurability capability + tests
  • Add PrefectDurability capability + tests

🤖 Generated with Claude Code

@github-actions github-actions bot added size: XL Extra large PR (>1500 weighted lines) feature New feature request, or PR implementing a feature (enhancement) labels Apr 4, 2026
DouweM and others added 2 commits April 4, 2026 05:33
…s, ReplayStreamedResponse

Foundation for porting TemporalAgent/DBOSAgent/PrefectAgent to capabilities:

- Add `toolset_id: str | None` to ToolDefinition, auto-populated from toolset
  in CombinedToolset.get_tools() — enables per-toolset config in capability hooks
- Add `wrap_get_tools(ctx, *, toolset, handler)` hook to AbstractCapability —
  allows capabilities to intercept tool listing I/O (e.g. MCP list_tools)
- Add `ReplayStreamedResponse` that converts a completed ModelResponse into
  synthetic PartStart/PartDelta/PartEnd events — enables transparent streaming
  when wrap_model_request short-circuits
- Use ReplayStreamedResponse in _agent_graph.py streaming short-circuit path
  (replaces _SkipStreamedResponse which yielded no events)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…y hooks

Introduces TemporalDurability, an AbstractCapability that routes model
requests and tool execution through Temporal activities using the capability
hook system (wrap_model_request, wrap_run, get_wrapper_toolset) instead of
requiring WrapperAgent/WrapperModel subclasses.

- wrap_model_request: intercepts model calls inside workflows, serializes
  request context, and routes to request_activity or request_stream_activity
- wrap_run: disables threads and catches PydanticSerializationError in workflows
- get_wrapper_toolset: swaps leaf toolsets with pre-created Temporal wrappers
- Model registry with identity + model_id string matching
- DurabilityPlugin for worker activity registration
- Rename _RequestParams → RequestParams for cross-module sharing
- Fix ReplayStreamedResponse type narrowing for PartStartEvent.index

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@DouweM DouweM force-pushed the temporal-durability-cap branch from 271c5f8 to 1e8bbd1 Compare April 4, 2026 20:30
@github-actions github-actions bot added size: L Large PR (501-1500 weighted lines) and removed size: XL Extra large PR (>1500 weighted lines) labels Apr 4, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 4, 2026

Docs Preview

commit: e519fb4
Preview URL: https://42f9d9bb-pydantic-ai-previews.pydantic.workers.dev

@DouweM DouweM force-pushed the temporal-durability-cap branch 2 times, most recently from ec1b2f4 to a9b627e Compare April 4, 2026 21:22
…for toolset_id

- DBOSDurability: routes model requests through @dbos.step(), wraps MCP toolsets
- PrefectDurability: routes model requests through @task, wraps toolsets via prefectify_toolset
- Both are transparent outside their respective workflow/flow contexts
- Fix OpenAIModel → OpenAIChatModel in docstring examples
- Update snapshots for new toolset_id field on ToolDefinition
- Update docs examples output for toolset_id

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@DouweM DouweM force-pushed the temporal-durability-cap branch from a9b627e to af54121 Compare April 4, 2026 21:52
Capabilities can now declare ordering constraints via `get_ordering()`:
- `position='outermost'`: must be first in the middleware chain (e.g. instrumentation)
- `position='innermost'`: must be last, closest to handler (e.g. durability)
- `before`/`after`: relative ordering between specific capability types
- `requires`: assert another capability type is present

CombinedCapability auto-sorts in __post_init__ when any child declares
constraints. Uses Kahn's algorithm with original-index tiebreaking for
stability. Zero overhead when no constraints exist.

All three durability capabilities declare position='innermost'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions bot added size: XL Extra large PR (>1500 weighted lines) and removed size: L Large PR (501-1500 weighted lines) labels Apr 4, 2026
…lication

- Change TemporalDurability from `models={'default': m}` to `model=m`
  with optional `models` dict for additional runtime models
- Add `get_toolset()` to all three durability capabilities so the agent
  automatically picks up toolsets — no need to pass them separately
- Expose `durability.model` so users can write `Agent(model=durability.model)`
- Update tests and docstring examples for the cleaner API

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature request, or PR implementing a feature (enhancement) size: XL Extra large PR (>1500 weighted lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant