Skip to content

feat(tui): FauxStep::Factory for live request-shape assertions#2107

Open
mvanhorn wants to merge 1 commit into
Hmbown:mainfrom
mvanhorn:osc/2074-faux-step-factory
Open

feat(tui): FauxStep::Factory for live request-shape assertions#2107
mvanhorn wants to merge 1 commit into
Hmbown:mainfrom
mvanhorn:osc/2074-faux-step-factory

Conversation

@mvanhorn
Copy link
Copy Markdown

Closes #2074.

Shape

pub enum FauxStep {
    Canned(CannedTurn),
    Factory(Box<dyn Fn(&MessageRequest) -> CannedTurn + Send + Sync>),
}

When a Factory step is dequeued, its closure runs against the real outgoing MessageRequest before the response stream is built, so any assert! panic surfaces directly from the client call rather than later in stream polling. No change to existing canned-turn callers.

Public surface

  • MockLlmClient::new(Vec<CannedTurn>) and push_turn(CannedTurn) keep working — they wrap each turn in FauxStep::Canned.
  • push_factory(closure) is new, for tests that want the Factory branch.
  • Doc comment on FauxStep::Factory captures the V4 thinking-mode tool-call invariant (the v0.4.9-v0.5.1 reasoning_content drop that produced HTTP 400 on follow-up turns).

Tests

  • New regression file crates/tui/tests/reasoning_content_replayed_after_tool_call.rs whose factory asserts the assistant tool-call turn carries a Thinking content block after a thinking + tool-call round. Mirrors the #[path = "..."] test-support pattern already used by integration_mock_llm.rs.
  • One additional unit test in mock.rs (create_message_synthesizes_from_factory_turn) for the non-streaming path.
  • Existing integration_mock_llm suite (27 tests) is unchanged and passes.
cargo test -p codewhale-tui --test reasoning_content_replayed_after_tool_call
  ... 20 passed; 0 failed
cargo test -p codewhale-tui --test integration_mock_llm
  ... 27 passed; 4 ignored
cargo fmt --check  ... clean

Known limitation

The new regression test asserts against a follow-up request the test itself assembles (with assistant_thinking_tool_call(...)), not one produced by the real turn-loop. That matches the issue's "Acceptance" wording (request.messages.last().reasoning_content.is_some()) and the integration_mock_llm.rs doc-comment which already notes the engine still holds a concrete Option<DeepSeekClient> rather than Arc<dyn LlmClient> — until that wiring lands, the mock can't be wedged into the real turn-loop. This PR delivers the FauxStep::Factory infrastructure the issue asks for; the engine-level wiring is the follow-up the integration_mock_llm.rs ignored tests already track.

AI was used for assistance.

Closes Hmbown#2074

Adds FauxStep::Factory(Box<dyn Fn(&MessageRequest) -> CannedTurn + Send + Sync>)
to MockLlmClient. When a Factory step is dequeued, its closure runs
against the real outgoing MessageRequest before the response stream is
built, so any assert! panic surfaces directly from the client call
instead of later in stream polling.

Internal storage moves from VecDeque<CannedTurn> to VecDeque<FauxStep>,
but every existing public method keeps working:

- MockLlmClient::new(Vec<CannedTurn>) wraps each turn in FauxStep::Canned.
- push_turn(CannedTurn) appends as FauxStep::Canned.

Adds push_factory(closure) for tests that want the Factory branch.

Doc comment on the Factory variant captures the DeepSeek V4
thinking-mode tool-call invariant (the v0.4.9-v0.5.1 reasoning_content
drop that produced HTTP 400 on follow-up turns).

Adds:

- crates/tui/tests/reasoning_content_replayed_after_tool_call.rs — a
  regression test whose factory asserts the assistant tool-call turn
  carries a Thinking content block after a thinking + tool-call round.
- An additional unit test in mock.rs covering create_message_synthesizes_from_factory_turn.

All 20 tests in the new file pass, and the existing
integration_mock_llm suite (27 tests) is unchanged.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the MockLlmClient by introducing FauxStep, an enum that allows for both static canned responses and dynamic response generation via a factory closure. This update enables more sophisticated testing by allowing assertions on outgoing MessageRequest objects directly within the mock. A new integration test was also added to ensure that reasoning_content is preserved in follow-up requests after tool calls, specifically targeting DeepSeek V4 requirements. I have no feedback to provide.

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.

MockLlmClient: turn-factory closures for live request-shape assertions

1 participant