fix: apply assistant-prefill guard to Anthropic models in interactive mode#469
Conversation
…ix#294) Two related fixes for reports not being saved when Strix exits: 1. Call tracer.cleanup() in main.py's finally block before posthog.end() so that run data is always written to disk regardless of whether the atexit handlers registered in cli.py/tui.py fire (they can be skipped on Windows when the asyncio event loop tears down). 2. Replace the strict all-or-nothing validation in finish_actions.py with a graceful fallback: missing fields get the placeholder "[Not provided by model]" so partial reports are saved rather than silently discarded when the LLM omits a section. Co-Authored-By: Octopus <liyuan851277048@icloud.com>
… mode (fixes usestrix#416) When interactive mode is enabled (TUI), the guard that prevents sending a trailing assistant message to the Anthropic API was incorrectly skipped. The Anthropic API rejects such requests with "This model does not support assistant message prefill." regardless of whether the caller is in interactive or non-interactive mode. Updated the condition to also apply the guard when `_is_anthropic()` is true, so Anthropic models are always protected while non-Anthropic models that may support assistant prefill continue to be unaffected in interactive mode. Added three unit tests covering all three branches of the new condition. Co-Authored-By: Octopus <liyuan851277048@icloud.com>
Greptile SummaryThis PR fixes the Anthropic assistant-prefill error in interactive mode by extending the trailing-assistant-message guard in
Confidence Score: 3/5Safe to merge the core Anthropic guard fix; the finish_actions.py behavioral change around validation warrants review before merging The primary fix in llm.py is correct and tested. However, the finish_actions.py change introduces a P1 behavioral regression: empty required report fields are silently substituted with placeholders and returned as success, removing the model's opportunity to self-correct and potentially producing incomplete scan reports without any in-session indication. strix/tools/finish/finish_actions.py — validation-to-placeholder behavior change needs deliberate design decision Important Files Changed
Prompt To Fix All With AIThis is a comment left during a code review.
Path: strix/tools/finish/finish_actions.py
Line: 102-106
Comment:
**Silent placeholder substitution removes model self-correction opportunity**
Previously, if the model provided empty strings for required report fields, the function returned a structured error (`{"success": False, ...}`), giving the model a chance to retry with actual content. After this change, empty fields are silently replaced with `"[Not provided by model]"` and the scan is marked `success: True`. The model never learns that its output was incomplete, so it cannot retry — the user receives a scan report with placeholder text and no in-session opportunity for the model to fill in the missing data.
If the intent is to prevent infinite retry loops, a middle path would be to return a soft warning in the success response, or to log/surface the placeholder substitution to the user at completion time.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix: apply assistant-prefill guard to An..." | Re-trigger Greptile |
| _NOT_PROVIDED = "[Not provided by model]" | ||
| executive_summary = (executive_summary or "").strip() or _NOT_PROVIDED | ||
| methodology = (methodology or "").strip() or _NOT_PROVIDED | ||
| technical_analysis = (technical_analysis or "").strip() or _NOT_PROVIDED | ||
| recommendations = (recommendations or "").strip() or _NOT_PROVIDED |
There was a problem hiding this comment.
Silent placeholder substitution removes model self-correction opportunity
Previously, if the model provided empty strings for required report fields, the function returned a structured error ({"success": False, ...}), giving the model a chance to retry with actual content. After this change, empty fields are silently replaced with "[Not provided by model]" and the scan is marked success: True. The model never learns that its output was incomplete, so it cannot retry — the user receives a scan report with placeholder text and no in-session opportunity for the model to fill in the missing data.
If the intent is to prevent infinite retry loops, a middle path would be to return a soft warning in the success response, or to log/surface the placeholder substitution to the user at completion time.
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/tools/finish/finish_actions.py
Line: 102-106
Comment:
**Silent placeholder substitution removes model self-correction opportunity**
Previously, if the model provided empty strings for required report fields, the function returned a structured error (`{"success": False, ...}`), giving the model a chance to retry with actual content. After this change, empty fields are silently replaced with `"[Not provided by model]"` and the scan is marked `success: True`. The model never learns that its output was incomplete, so it cannot retry — the user receives a scan report with placeholder text and no in-session opportunity for the model to fill in the missing data.
If the intent is to prevent infinite retry loops, a middle path would be to return a soft warning in the success response, or to log/surface the placeholder substitution to the user at completion time.
How can I resolve this? If you propose a fix, please make it concise.Greptile review noted the placeholder substitution was silent — adding a warning log when fields are missing makes the substitution visible to operators while keeping the partial-report save behavior intact. The placeholder approach (vs returning a validation error) is intentional — losing the entire scan because the model omitted one section was the original bug from usestrix#294, so the trade-off favors saving the report. Co-Authored-By: Octopus <liyuan851277048@icloud.com>
|
Good catch — partially addressed in 7259ffe by adding a Keeping the placeholder behavior (rather than returning a validation error) is intentional for this PR — see the commit message on 8e25743 and the issue #294 it fixes. The original strict validation was silently discarding entire scans when the model omitted one section, which was worse than saving a partial report. The model retry path was effectively never exercised because the scan was already winding down by the time If the partial-report behavior turns out to mask real model failures in practice, surfacing the placeholder count back to the user at completion time (per your middle-path suggestion) is a clean follow-up. |
Fixes #416
Problem
When running Strix in interactive (TUI) mode with an Anthropic model (e.g. Claude Sonnet 4.6), users eventually encounter:
The root cause:
_prepare_messagescontains a guard that appends a synthetic<meta>Continue the task.</meta>user message whenever the conversation history ends with an assistant message. However, since commit 1404864 ("feat: add interactive mode"), this guard was gated behindand not self.config.interactive, so it was silently skipped for the TUI.The Anthropic API rejects trailing assistant messages regardless of whether the call originates from interactive or non-interactive mode. Any edge case that leaves the conversation ending with an assistant message (cancelled request, state recovery, sub-agent resume after timeout) would trigger the error in TUI mode.
Solution
Extend the condition to also apply the guard when
self._is_anthropic()is true:This ensures:
Testing
Added
tests/llm/test_prepare_messages.pywith three unit tests covering each branch of the condition. All tests pass.