Skip to content

fix(orchestrator): prevent duplicate assistant egress on model_error turns - #229

Open
eldonm wants to merge 6 commits into
mainfrom
fix/duplicate-assistant-egress
Open

eldonm wants to merge 6 commits into
mainfrom
fix/duplicate-assistant-egress

Conversation

@eldonm

@eldonm eldonm commented Sep 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Gate _after_loop / _egress on _turn_delivered() so streaming has_emitted() and interaction.response cannot both trigger a second compose on model_error turns.
  • Harden commit_pending_adhoc to skip replay when settled text is already on interaction.response and latch mark_emitted.
  • ResponseBus single-egress latch: first delivered non-transient user stream chunk marks the Interaction emitted; later independent user publishes for the turn are suppressed at the framework boundary (fixes twin bubbles without consumer text-normalize).
  • Unblock CI: derive LiteLLM context_window from litellm_capabilities() instead of hard-coded 200k.

Test plan

  • pytest tests/action/orchestrator/test_model_error_intro_single_egress.py tests/action/orchestrator/test_model_failure.py
  • pytest tests/action/response/test_emitted_latch.py
  • pytest tests/action/model/test_litellm_action.py::test_capabilities_and_pricing_come_from_upstream_metadata
  • Full pytest via pre-push hook
  • Local integral-core smoke: single assistant bubble after model turn

Eldon Marks and others added 6 commits September 13, 2026 22:59
Drop graph-repair edge_ids sync phases; pin jvspatial==0.0.19.
…turns

_after_loop gated only on interaction.response while streaming latches
emitted first, so model_unavailable compose could run twice. Unify delivery
detection via _turn_delivered and skip commit_pending_adhoc when the settled
text is already on the interaction.

Co-authored-by: Cursor <cursoragent@cursor.com>
Hard-coded 200k for claude-sonnet-4-5 broke when LiteLLM bumped the
model table to 1M; assert against litellm_capabilities() instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
_after_loop already used _turn_delivered; _egress still checked
has_emitted() only, so a turn with interaction.response set but no latch
(model_error salvage path) queued a second ReplyAction publish. Also latch
emitted when commit_pending_adhoc skips an already-settled replay.

Co-authored-by: Cursor <cursoragent@cursor.com>
MagicMock interactions expose a truthy non-string response attribute;
_turn_delivered must check isinstance(str) before skipping egress.

Co-authored-by: Cursor <cursoragent@cursor.com>
…hunk

Stops a second independent user publish from twinning assistant bubbles
downstream; active stream may still finish. Covered by emitted-latch tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

1 participant