fix(streaming): rationalize thinking retrieval vs model budget - #1853
fix(streaming): rationalize thinking retrieval vs model budget#1853arimu1 wants to merge 4 commits into
Conversation
agree 100% |
ace908d to
9c14b29
Compare
|
Addressed review feedback and rebased onto current
Happy to iterate further if anything still looks off. |
igordayen
left a comment
There was a problem hiding this comment.
@arimu1 - thank you. started with larger design, please take a look and provide your comments.
And please confirm whether you are planning to execute IT test.
Also: please mark as "resolved" this outstanding inquiries - im referring to only ones that are actully resolved.
Thanks
|
Thanks @jorander and @igordayen — summarizing how the latest tip addresses the review threads: Docs (jorander / igordayen)The streaming docs now explicitly separate:
Model thinking budget ( Naming (igordayen)
IT testsI am not planning a full multi-provider IT in this PR — coverage is unit-level ( Review threadsPlease take another look at tip |
|
@jorander @igordayen Follow-up: all review threads are now resolved (including the FYI ping). Tip remains
Happy to adjust further if anything still looks off after re-review. |
de94e38 to
613fd15
Compare
|
Fixed DCO: tip commit |
|
@arimu1 - thank you for contributing. May I suggest? Regarding the introduction of the "thinking format" parameter.
|
Remove the separate includeThinkingFormat SPI parameter. Application-level prompt format now follows Thinking.extractThinking on the Interaction (enabled via withExtraction/applyExtraction); provider tokenBudget remains independent (Thinking.enabled). WithThinking paths ensure extractThinking is set so format propagates through Interaction only. Addresses igordayen design feedback on embabel#1853 / embabel#1799. Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com>
613fd15 to
4d2dca1
Compare
|
@igordayen Thanks for the design pushback — you were right that a separate SPI Answer to your questionsIntent: yes — auto-enable application-level (prompt-instructed) thinking for Is
Why
|
|
@arimu1 - thank you for moving this forward. Could you please consider adding a test for this into LLMOllamaStreamingBuilderIT.java. |
createObjectStreamWithThinking always enables thinking format instructions and extraction, independent of Thinking.withTokenBudget. Object-only streams omit thinking format. Document the split. Fixes embabel#1799. Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com>
…nsTest Address review feedback to use imports instead of fully qualified names. Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com>
Remove the separate includeThinkingFormat SPI parameter. Application-level prompt format now follows Thinking.extractThinking on the Interaction (enabled via withExtraction/applyExtraction); provider tokenBudget remains independent (Thinking.enabled). WithThinking paths ensure extractThinking is set so format propagates through Interaction only. Addresses igordayen design feedback on embabel#1853 / embabel#1799. Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com>
Add LLMOllamaStreamingBuilderIT coverage for createObjectStreamWithThinking without tokenBudget, with tokenBudget (applyExtraction), and object-only stream with budget alone — validates application-level extractThinking is independent of provider Thinking.withTokenBudget (embabel#1799 / embabel#1853). Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com>
4d2dca1 to
b497c7d
Compare
|
@igordayen Thanks — added the IT coverage in New test:
|
==> so path C is the only negative test then, thanks |
| private fun streamingInteractionForThinkingIfNecessary(): LlmInteraction { | ||
| val base = streamingInteraction() | ||
| val thinking = when (val existing = llm.thinking) { | ||
| null, Thinking.NONE -> Thinking.withExtraction() |
There was a problem hiding this comment.
Could you please explain the logic and how it actually behaves
| */ | ||
| private fun withApplicationLevelThinkingIfNecessary(interaction: LlmInteraction): LlmInteraction { | ||
| val existing = interaction.llm.thinking | ||
| val thinking = when (existing) { |
| val chatOptions = requireSpringAiLlm(llm).convertOptions(interaction.llm) | ||
|
|
||
| // Application-level thinking format: Thinking.extractThinking (not provider tokenBudget / enabled). | ||
| val includeApplicationLevelThinking = interaction.llm.thinking?.extractThinking == true |
There was a problem hiding this comment.
do you need this "val" , or just interaction.llm.thinking?.extractThinking == true use as is
| private fun withApplicationLevelThinkingIfNecessary(interaction: LlmInteraction): LlmInteraction { | ||
| val existing = interaction.llm.thinking | ||
| val thinking = when (existing) { | ||
| null, Thinking.NONE -> Thinking.withExtraction() |
There was a problem hiding this comment.
3rd occurrence of dup code
|
@guanxuc @igordayen Thanks — please go ahead with the shared |
Thanks @igordayen — I'll pick up the remaining code maintenance items:
Hi @igordayen , @arimu1 , I've pushed commit guanxuc@6a4434f to address the code maintenance items raised in the review. Unfortunately, I don't have push access to @arimu1's fork, so I've pushed it to my own fork instead: |
Hi @arimu1, Since I don't have push access to your fork, I'll open a PR from my fork targeting your branch if the commit guanxuc@6a4434f looks good. |
Hi @igordayen , Got it, thanks for letting us know! We’ll pause this week and resume after the release. Good luck with the upgrade 🚀! For clarity, please note that ownership of this PR rests with @arimu1. |
Summary
Fixes #1799 — rationalize thinking in streaming mode.
Streaming previously gated thinking format instructions on
LlmOptions.thinking.enabled(typically only set viaThinking.withTokenBudget(...)). That madecreateObjectStreamWithThinkingfeel like it required a token budget as a prerequisite, even though retrieving thinking events and configuring a model thinking budget are separate concerns (as discussed with @jorander on the issue).Changes
createObjectStreamWithThinkingalways enables thinking format instructions so callers get reasoning blocks without pre-configuring a budget.createObjectStreamnever injects thinking format instructions (object-only path; avoids pushing models to think and then discarding the content — consistent with StreamingJacksonOutputConverter pushes models to think even when thinking is disabled #1685/StreamingJacksonOutputConverter.getFormat() respects disabled thinking #1687 intent for non-thinking streams).OperationContextDelegate): enable extraction for the with-thinking stream while preserving any existing token budget viaThinking.applyExtraction().streaming/page.adoc): document retrieval vs model budget, with optional Anthropic-style budget example.Model thinking budget remains optional and independent:
No auto-default token budget and no warning log (per maintainer feedback on #1799).
AI assistance
Assisted by AI (Grok). Human author: arimu1.
Test plan
StreamingChatClientOperationsTest(25 tests) including:createObjectStreamWithThinking includes thinking format without LlmOptions thinking configcreateObjectStream omits thinking format instructions