Skip to content

temporal-spring-ai: accept ActivityOptions and classify non-retryable AI errors#2853

Open
donald-pinckney wants to merge 5 commits intospring-ai/activity-summariesfrom
spring-ai/retry-and-options
Open

temporal-spring-ai: accept ActivityOptions and classify non-retryable AI errors#2853
donald-pinckney wants to merge 5 commits intospring-ai/activity-summariesfrom
spring-ai/retry-and-options

Conversation

@donald-pinckney
Copy link
Copy Markdown
Contributor

@donald-pinckney donald-pinckney commented Apr 21, 2026

Based on

Merge that first; this PR will auto-retarget to master.


What was changed

  • ActivityChatModel.forDefault(ActivityOptions) and forModel(String, ActivityOptions) overloads added. New public defaultActivityOptions() returns the plugin's default bundle so callers can tweak one field (e.g., task queue) without losing the other sensible defaults.
  • ActivityMcpClient.create(ActivityOptions) + defaultActivityOptions() added, mirroring the chat side.
  • Default RetryOptions for chat calls now mark org.springframework.ai.retry.NonTransientAiException and java.lang.IllegalArgumentException non-retryable. Default options for MCP calls mark IllegalArgumentException non-retryable. User-supplied ActivityOptions pass through verbatim — the plugin does not augment them.
  • The public new ActivityChatModel(...) and new ActivityMcpClient(activity) constructors are removed. The factories are now the sole construction path. The module is pre-release so there are no pinned callers to migrate; the deprecate-then-remove cycle would be pure noise.
  • README: new "Activity options and retry behavior" section documents the defaults and how to customize via the ActivityOptions overload.
  • Tests: two new suites — ActivityOptionsAndRetryTest covers non-retryable classification (1 attempt for NonTransientAiException, 3 attempts for transient RuntimeException, custom task queue landing on the scheduled activity); ActivitySummaryTest gains a regression test asserting forDefault(customOptions) still emits UI Summaries.
  • build.gradle: spring-ai-retry added as a testImplementation so tests can reference NonTransientAiException directly.

Why?

Two gaps the integration guide calls out:

  1. Retry classification. Without a doNotRetry list, a bad API key or invalid-prompt error churned through retries + backoff before failing. The new defaults fail fast on clearly permanent failures while still retrying transient ones (network, 5xx, rate-limits).
  2. Customization surface. The prior factory API only exposed (timeout, maxAttempts) — no heartbeats, task queue override, priority, or doNotRetry. Users hitting those needs had to call the public constructor with a hand-built stub. That path silently dropped the UI Summary labels the summaries branch (temporal-spring-ai: attach activity summaries for chat and MCP calls #2852) added, so users were forced to choose between customization and readability.

The new ActivityOptions overloads give users both. Removing the public constructors outright means users can't accidentally end up in a code path that skips UI labels — there's one way in, and it does the right thing.

Depends on #2852 (activity-summaries). The summary regression test in this PR only passes because that branch already landed the baseOptions plumbing the new overloads thread through.

@donald-pinckney donald-pinckney force-pushed the spring-ai/retry-and-options branch from 2a76e4e to f967316 Compare April 21, 2026 21:19
@donald-pinckney donald-pinckney changed the base branch from master to spring-ai/activity-summaries April 21, 2026 22:04
@donald-pinckney donald-pinckney force-pushed the spring-ai/retry-and-options branch from f967316 to 1310ba4 Compare April 22, 2026 16:07
donald-pinckney and others added 2 commits April 22, 2026 12:56
…e error classification

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ies UX wart

The activity-summaries branch only overlays Summaries when the factories
(forModel/create) built the stub. Users who need custom timeouts today fall
back to the public constructor, which silently drops UI Summaries. The
ActivityOptions overloads planned here are the proper fix: they let users
customize the stub and keep Summary labels. Plan now also covers deprecating
the public constructors with javadoc pointing at the factories.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@donald-pinckney donald-pinckney force-pushed the spring-ai/retry-and-options branch 2 times, most recently from 14f61a6 to f038d46 Compare April 22, 2026 17:53
donald-pinckney and others added 3 commits April 22, 2026 15:10
… AI errors

- ActivityChatModel.forDefault(ActivityOptions) and forModel(String,
  ActivityOptions) overloads added. New public defaultActivityOptions()
  returns the plugin's default bundle so callers can tweak one field
  without losing the other sensible defaults.
- ActivityMcpClient.create(ActivityOptions) + defaultActivityOptions()
  added, mirroring the chat side.
- Default RetryOptions for chat calls now mark
  org.springframework.ai.retry.NonTransientAiException and
  java.lang.IllegalArgumentException non-retryable. Default options for
  MCP calls mark IllegalArgumentException non-retryable. User-supplied
  ActivityOptions pass through verbatim — the plugin does not augment
  them.
- new ActivityChatModel(...) and new ActivityMcpClient(activity)
  constructors are @deprecated with javadoc pointing at the factories —
  they still work at runtime but skip the UI Summary labels the
  plugin-owned stub path attaches, which is now called out explicitly.
- README: new "Activity options and retry behavior" section documents
  the defaults, how to customize, and the Summary/factory connection.
- Tests: two new suites — ActivityOptionsAndRetryTest covers the
  non-retryable classification (1 attempt for NonTransientAiException,
  3 attempts for transient RuntimeException, custom task queue landing
  on the scheduled activity); ActivitySummaryTest gains a regression
  test asserting forDefault(customOptions) still emits UI Summaries.
- build.gradle: spring-ai-retry added as a testImplementation so tests
  can reference NonTransientAiException directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Planning scratchpad — not part of the shipped artifact. Removed before merge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Now that forDefault(ActivityOptions) / forModel(String, ActivityOptions)
/ create(ActivityOptions) exist, the (Duration, int) convenience
overloads are asymmetric dead weight — they expose two of N ActivityOptions
fields as positional parameters, and callers wanting anything else
(heartbeats, task queue, custom retry backoff, ...) have to drop to the
ActivityOptions path anyway. Removed pre-release so the API surface is
consistent: no-arg → plugin defaults; ActivityOptions arg → caller options.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@donald-pinckney donald-pinckney force-pushed the spring-ai/retry-and-options branch from f038d46 to 9528294 Compare April 22, 2026 19:10
@donald-pinckney donald-pinckney marked this pull request as ready for review April 22, 2026 19:50
@donald-pinckney donald-pinckney requested a review from a team as a code owner April 22, 2026 19:50
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.

1 participant