Skip to content

fix(core): register MagicDocs on tool-result push, not only assistant push - #6160

Merged
bug-ops merged 1 commit into
mainfrom
fix/6127-magicdocs-bare-mode
Jul 12, 2026
Merged

fix(core): register MagicDocs on tool-result push, not only assistant push#6160
bug-ops merged 1 commit into
mainfrom
fix/6127-magicdocs-bare-mode

Conversation

@bug-ops

@bug-ops bug-ops commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • MagicDocs registration never fired for a single read-then-respond turn (the canonical --bare -p "read X" shape), or for a turn that exited the native tool loop via shutdown/user-cancel/doom-loop/max-iterations with an unpaired tool result as the last message.
  • Root cause: detect_magic_docs_in_messages() only scanned when the last pushed message was Role::Assistant, deferring detection to the next assistant push. Two terminal-response sites in tier_loop.rs also bypassed push_message() via a raw self.msg.messages.push(), so the detector never ran for the turn's final response.
  • Fix: both raw pushes now route through push_message(), and the detection guard also scans when the last message is a Role::User message carrying ToolResult/ToolOutput parts, so detection fires uniformly at the point content actually arrives, covering all native-loop exit paths (not just the two terminal push sites).
  • Side effect: the two corrected push sites now also update cached_prompt_tokens and last_assistant_at, closing a pre-existing token-accounting gap on the semantic-cache-hit and plain-text-response paths.
  • Not a --bare-conditional gate: with_bare_mode required no change. This was a general tool-loop message-push coverage gap that --bare's single-shot invocation pattern exposed deterministically; interactive multi-tool-call sessions usually masked it via a retroactive scan on the next assistant push.

Closes #6127

Test plan

  • Added 3 regression tests in crates/zeph-core/src/agent/tool_execution/tests/sanitize_and_native_tests.rs, each driving the real Agent::process_response() path (not a hand-built message history): single read-then-respond turn, semantic-cache-hit branch, and loop-exit via max_iterations exhaustion with an unpaired trailing tool result. All confirmed to fail on pre-fix code and pass on the fix.
  • cargo +nightly fmt --check clean
  • cargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings clean
  • cargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins — 13180 passed, 35 skipped, no regressions
  • RUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --workspace --features "desktop,ide,server,chat,pdf,scheduler" clean
  • CHANGELOG.md updated
  • Testing playbook and coverage-status.md updated

@github-actions github-actions Bot added the bug Something isn't working label Jul 12, 2026
@bug-ops
bug-ops enabled auto-merge (squash) July 12, 2026 18:28
@github-actions github-actions Bot added size/L Large PR (201-500 lines) documentation Improvements or additions to documentation rust Rust code changes core zeph-core crate labels Jul 12, 2026
@bug-ops
bug-ops force-pushed the fix/6127-magicdocs-bare-mode branch from 16c6c2a to be2d2fb Compare July 12, 2026 18:33
… push

MagicDocs registration never fired for a single read-then-respond turn
(the canonical `--bare -p "read X"` shape) or for a turn that exited
the native tool loop via shutdown/user-cancel/doom-loop/max-iterations
with an unpaired tool result as the last message.

detect_magic_docs_in_messages() only scanned when the last pushed
message was Role::Assistant, deferring detection to the next assistant
push. Two terminal-response sites in tier_loop.rs also bypassed
push_message() entirely via a raw self.msg.messages.push(), so the
detector never ran for the turn's final text response. Both raw pushes
now route through push_message(), and the detection guard also scans
when the last message is a Role::User message carrying
ToolResult/ToolOutput parts, so detection fires uniformly at the point
the content actually arrives, covering all native-loop exit paths.

As a side effect, the two corrected push sites now also update
cached_prompt_tokens and last_assistant_at, closing a pre-existing
token-accounting gap on the semantic-cache-hit and plain-text-response
paths.

Not a `--bare`-conditional gate: with_bare_mode required no change.
This was a general tool-loop message-push coverage gap that --bare's
single-shot invocation pattern exposed deterministically.

Closes #6127
@bug-ops
bug-ops force-pushed the fix/6127-magicdocs-bare-mode branch from be2d2fb to 5d3817f Compare July 12, 2026 18:43
@bug-ops
bug-ops merged commit 5ab24a9 into main Jul 12, 2026
43 checks passed
@bug-ops
bug-ops deleted the fix/6127-magicdocs-bare-mode branch July 12, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working core zeph-core crate documentation Improvements or additions to documentation rust Rust code changes size/L Large PR (201-500 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MagicDocs registration never fires in --bare mode despite [magic_docs] enabled=true

1 participant