Skip to content

temporal-spring-ai: add side-effect replay tests for chat, activity tools, and @SideEffectTool#2856

Open
donald-pinckney wants to merge 3 commits intomasterfrom
spring-ai/sideeffect-replay-tests
Open

temporal-spring-ai: add side-effect replay tests for chat, activity tools, and @SideEffectTool#2856
donald-pinckney wants to merge 3 commits intomasterfrom
spring-ai/sideeffect-replay-tests

Conversation

@donald-pinckney
Copy link
Copy Markdown
Contributor

What was changed

Three new tests under src/test/.../replay/:

  • ChatModelSideEffectTest — register a ChatModel with an AtomicInteger counter. Run a workflow that makes one chat call, assert counter=1. Replay the captured history, assert counter still 1 — the activity result comes from history, not from re-invoking the ChatModel.
  • ActivityToolSideEffectTest — activity-backed @Tool whose impl increments a counter. A tool-calling stub ChatModel asks for the tool on the first call and returns final text on the second. Same shape: counter=1 after run, counter=1 after replay.
  • SideEffectToolReplayTest@SideEffectTool body increments a file-scope counter. The workflow drives one tool call. Assertion proves that Workflow.sideEffect's marker is consulted on replay rather than re-invoking the @Tool method.

MCP is intentionally omitted for this PR. spring-ai-mcp is compileOnly, and adding it just for one replay test isn't worth the dep weight — MCP tool calls go through the same Temporal activity machinery as ChatModel, which ChatModelSideEffectTest already exercises. The plan leaves this as an acceptable substitution.

Why?

The existing WorkflowDeterminismTest catches history-vs-command mismatches but does not prove the plugin isn't re-invoking user side effects on replay. Temporal's AI partner review standards require side-effect safety tests, and a regression — someone adding an in-workflow cache or dropping the Workflow.sideEffect wrap — would be easy to slip in without these.

I verified the SideEffectToolReplayTest actually catches a real regression: temporarily dropping the Workflow.sideEffect(...) wrap in SideEffectToolCallback.call(...) produces expected: <1> but was: <2> exactly as intended. Restored before this commit.

donald-pinckney and others added 3 commits April 21, 2026 15:54
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ools, and @SideEffectTool

Three new tests under src/test/.../replay/:

- ChatModelSideEffectTest: register a ChatModel with an AtomicInteger
  counter. Run a workflow that makes one chat call, assert counter=1.
  Replay the captured history, assert counter still 1 — the activity
  result comes from history, not from re-invoking the ChatModel.
- ActivityToolSideEffectTest: activity-backed @tool whose impl
  increments a counter. ToolCallingStubChatModel asks for the tool on
  the first call and returns final text on the second. Same assertion
  shape: counter=1 after run, counter=1 after replay.
- SideEffectToolReplayTest: @SideEffectTool body increments a counter
  via a file-scope static. Workflow drives a tool call through
  ToolCallingStubChatModel. The assertion proves that
  Workflow.sideEffect's marker is what's consulted on replay rather
  than re-invoking the @tool method.

MCP is intentionally omitted — spring-ai-mcp is compileOnly and adding
it just for one test isn't worth the dep weight. MCP tool calls go
through the same Temporal activity machinery as ChatModel, which
ChatModelSideEffectTest already covers.

I verified the SideEffectToolReplayTest catches a real regression by
temporarily dropping the Workflow.sideEffect wrap in
SideEffectToolCallback; the test correctly failed with
`expected: <1> but was: <2>`. Restored before this commit.

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>
@donald-pinckney donald-pinckney marked this pull request as ready for review April 22, 2026 19:52
@donald-pinckney donald-pinckney requested a review from a team as a code owner April 22, 2026 19:52
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