temporal-spring-ai: per-model ActivityOptions registry#2855
Open
donald-pinckney wants to merge 3 commits intospring-ai/retry-and-optionsfrom
Open
temporal-spring-ai: per-model ActivityOptions registry#2855donald-pinckney wants to merge 3 commits intospring-ai/retry-and-optionsfrom
donald-pinckney wants to merge 3 commits intospring-ai/retry-and-optionsfrom
Conversation
44777c8 to
316d52b
Compare
f967316 to
1310ba4
Compare
316d52b to
ba6a88a
Compare
1310ba4 to
9bb3866
Compare
bad7fd6 to
e8405cc
Compare
f038d46 to
9528294
Compare
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SpringAiPlugin now accepts an optional Map<String, ActivityOptions>
keyed by chat-model bean name. On construction the plugin publishes
the map to a new package-public static registry SpringAiPluginOptions,
which ActivityChatModel.forModel(name) and forDefault() consult when
building the activity stub. Entries resolve by bean name; the reserved
key SpringAiPlugin.DEFAULT_MODEL_NAME ("default") covers forDefault().
Callers who pass explicit ActivityOptions via forModel(name, options)
or forDefault(options) bypass the registry entirely — explicit options
always win. The registry has no effect on the (timeout, maxAttempts)
convenience factory either; that still builds options from its args.
Auto-configuration picks up a user bean named
"chatModelActivityOptions" (constant
SpringAiTemporalAutoConfiguration.CHAT_MODEL_ACTIVITY_OPTIONS_BEAN) of
type Map<String, ActivityOptions>. The explicit bean-name qualifier
avoids Spring's collection-of-beans auto-wiring for Map<String, T>.
Tests: PerModelActivityOptionsTest covers the three cases called out
in the plan — registry hit, registry miss (falls back to default
2-minute timeout), and explicit options bypass.
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>
e8405cc to
1a2adb2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Based on
spring-ai/activity-summaries— adds the chat/MCP Summary plumbingspring-ai/retry-and-options— adds theActivityOptionsfactory overloads anddefaultActivityOptions()this PR builds onMerge those in order first; this PR will retarget each time an ancestor lands.
What was changed
SpringAiPluginOptionsstatic registry (packageio.temporal.springai.plugin).SpringAiPluginpublishes aMap<String, ActivityOptions>to it on construction;ActivityChatModel.forModel(String)/forDefault()consult it before falling back to the plugin defaults.SpringAiPlugingains a third constructor that accepts the per-model map; the two existing constructors delegate with an empty map. No constructor changes to existingSpringAiPlugin(ChatModel)/SpringAiPlugin(Map, ChatModel)call sites.ChatModelActivityOptionsrecord (packageio.temporal.springai.autoconfigure) — a thin wrapper aroundMap<String, ActivityOptions>— exists soSpringAiTemporalAutoConfigurationcan inject user options by type rather than by bean name. RawMap<String, ActivityOptions>injection would trigger Spring's collection-of-beans autowiring and sweep in any unrelatedActivityOptionsbean in the context. Using a dedicated wrapper type avoids that collision and keeps the design consistent with temporal-spring-ai: discover MCP clients by type, not by bean name #2859 (MCP bean lookup by type, not by name).SpringAiTemporalAutoConfigurationinjectsObjectProvider<ChatModelActivityOptions>and forwards the wrapped map to the plugin. No magic bean name, no@Qualifier.ActivityOptionsviaforModel(name, options)/forDefault(options)bypass the registry entirely. The(timeout, maxAttempts)convenience factory is unaffected — it still builds options from its arguments.PerModelActivityOptionsTestcovers the three cases in the plan — registry hit uses the registeredstartToCloseTimeout, registry miss falls back to the 2-minute default, explicit options bypass a populated registry entry.Why?
A single default (2 min start-to-close, 3 attempts) doesn't fit every model. Reasoning and thinking-mode models need more time; fast models want shorter timeouts so retries recover quickly. The Temporal AI integration guide specifically calls this out as a capability partners should expose. With this change, users register one bean and never have to hand-build activity stubs again.
Example user config: