feat(llm): route reasoning models to reasoning-aware provider clients #106
Merged
CoreRasurae
merged 1 commits from 2026-08-05 22:19:58 +00:00
feature/m2-reasoning-model-provider-support into master
1 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
01ab2c8e9b |
feat(llm): route reasoning models to reasoning-aware provider clients
CI / lint (pull_request) Successful in 35s
CI / security (pull_request) Successful in 1m6s
CI / quality (pull_request) Successful in 35s
CI / typecheck (pull_request) Successful in 1m38s
CI / build (pull_request) Successful in 1m50s
CI / integration_tests (pull_request) Successful in 2m36s
CI / unit_tests (pull_request) Successful in 4m47s
CI / coverage (pull_request) Successful in 4m3s
CI / status-check (pull_request) Successful in 8s
CI / lint (push) Successful in 42s
CI / typecheck (push) Successful in 1m13s
CI / security (push) Successful in 1m12s
CI / quality (push) Successful in 1m47s
CI / build (push) Successful in 1m40s
CI / integration_tests (push) Successful in 4m48s
CI / unit_tests (push) Successful in 6m8s
CI / benchmark (pull_request) Failing after 22m54s
CI / coverage (push) Successful in 4m30s
CI / status-check (push) Successful in 6s
CI / benchmark (push) Failing after 17m0s
Non-native providers (openai_compatible and every named additional provider) were routed unconditionally to a bare langchain_openai.ChatOpenAI(base_url=...) client. That client silently drops reasoning_content on both the response and request legs, so a reasoning/"thinking" model behind an OpenAI-compatible endpoint that requires the reasoning block to be echoed back on the assistant turn preceding a tool result rejected the follow-up call with a non-transient 400 error, aborting the actor-graph execution. Adds an optional `reasoning` boolean field to the LLM agent configuration (default false, byte-identical behavior when absent/false or for native providers). When true on a non-native provider, build_chat_model now constructs cleveractors.agents.llm_reasoning.ReasoningChatModel, a thin langchain_deepseek.ChatDeepSeek subclass that overrides _get_request_payload to re-inject reasoning_content onto assistant turns, closing the round-trip that ChatDeepSeek alone leaves open. LLMAgent._execute_tool_loop needed no change: it already appends the returned AIMessage by reference, so additional_kwargs survives replay. ADR-2036 (approved) extends ADR-2028 with the full design record (client-selection strategy, response/request-leg responsibilities, alternatives considered). docs/index.md §4.4/§4.4.1 documents the new `reasoning` field as Version 1.3.0, with a §21.1 Revision History row attributing the change to ADR-2036 and a normative note that the routing applies regardless of single-response vs. streaming invocation. Adds a new mkdocs user guide, docs/guides/reasoning-aware-llm-agents.md (registered under a new "Guides" nav section in mkdocs.yml), covering practical usage: enabling the field, combining it with tool calling, and the concrete difference between Executor.execute() and Executor.execute_stream() — the latter runs the identical multi-turn tool-call loop and reasoning_content round-trip when tools are configured, differing only in delivering the finished answer as one chunk instead of token-by-token, which is a pre-existing property of streaming with tools in general, not something specific to reasoning. Addresses PR #106 review feedback from rui.hu: - Reformat features/steps/reasoning_provider_routing_steps.py with ruff so the lint CI job (and downstream coverage job) run again. - Clarify in ReasoningRoutingTestLib.py that stubbing only the OpenAI network boundary matches established precedent across every other *.robot suite in this project (ToolCallingTestLib, TokenBudgetTestLib, SkillLoadingTestLib all mock only the LLM API call for the same reason: integration tests must run without a real LLM API key). - Add a Behave scenario/steps mirroring the existing google-genai import-guard coverage test for the new _REASONING_AVAILABLE guard in llm_imports.py, closing a coverage gap the new guard introduced. Also corrects a rebase artifact in docs/index.md: this branch had regressed the Version header to 1.1.0 and silently dropped master's 1.2.0 `tools_max_timeout` tool-agent field (ADR-2030 D-9) along with its §21.1 Revision History row. Restored that content and the `reasoning` field now lands as its own 1.3.0 revision on top of it. ISSUES CLOSED: #101 |