Skip to content

fix(strix): disable streaming to route around contextual-orchestrator's stale invalid_stream_options rejection - #1447

Closed
seonghobae wants to merge 1 commit into
mainfrom
fix/strix-disable-streaming-orchestrator-usage-gap
Closed

fix(strix): disable streaming to route around contextual-orchestrator's stale invalid_stream_options rejection#1447
seonghobae wants to merge 1 commit into
mainfrom
fix/strix-disable-streaming-orchestrator-usage-gap

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Incident

Every Strix scan org-wide has been failing closed with a 400 since Strix moved to contextual-orchestrator's orchestrator/free pool today (#1434). Example failure: run 33307905354, job 99247611184.

Root cause, confirmed by reading actual source (strix v1.5.3, openai-agents v0.19.4, and contextual_orchestrator/server.py/orchestrator.py directly — not guessed):

  • strix-agent 1.5.3 hardcodes ModelSettings(include_usage=True) for every turn (strix/core/inputs.py::make_model_settings()), with no supported env var, CLI flag, or config key to disable just that flag while keeping streaming.
  • contextual_orchestrator/server.py (~line 6583-6589) unconditionally rejects stream=true + stream_options.include_usage=true whenever tools or response_format are present. Strix always sends tools, so every turn hits this. The check's own justification ("structured passthrough cannot emit usage SSE") is factually wrong: the tool-loop path already forces the upstream call to non-streaming and already captures real provider usage, and _chat_response_sse_chunks already builds a genuine usage_source: "reported" SSE chunk from it — the honest-usage plumbing this check thinks doesn't exist already exists and already runs on this exact path.

Fix (temporary mitigation)

Sets LLM_DISABLE_STREAMING: "true" in the Strix job env in strix.yml. This is a genuine, documented strix env var (strix/config/models.py::_NonStreamingModel) that makes every turn a single non-streaming call, so stream_options is never sent and the gateway's check never fires. Restores the required Strix gate immediately at the cost of real-time SSE streaming.

This is not the real fix — see #1446 for what must land in contextual-orchestrator (removing/narrowing the stale rejection, since the honest usage-reporting path it guards already works) before this line is reverted.

Developer experience

  • python3 -c "import yaml; yaml.safe_load(open('.github/workflows/strix.yml'))" — valid YAML.
  • Full suite: PYTHONPATH=. coverage run -m pytest tests -q → 1903 passed, 1 skipped (unchanged from before this commit).
  • Strix-specific contract tests (test_strix_contextual_orchestrator_contract.py, test_strix_nvidia_nim_not_found_fallback.py, test_strix_openai_fallback_api_base.py, test_strix_repository_visibility_contract.py, test_strix_backend_unavailable_after_exempted_finding.py, test_strix_local_proxy_bootstrap_failure_is_classified.py, test_strix_model_behavior_error.py): 68 passed.

User experience

None directly — CI-internal. Strix loses real-time streaming output during scans until the tracked contextual-orchestrator fix lands and this mitigation is reverted.

Test plan

  • YAML validity
  • Full test suite (1903 passed, 1 skipped)
  • Strix contract test files (68 passed)
  • Note: this PR's own strix required check will very likely fail on its own head — pull_request_target executes the workflow definition from the trusted base branch, not this PR's head, so the fix in this diff cannot apply to its own check run (the documented trust-boundary catch-22 for PRs editing strix.yml itself, docs/pr-review-and-merge-procedure.md). This is expected and not a defect in the diff.

Tracking: #1446


Generated by Claude Code


Devin Review

…'s stale invalid_stream_options rejection

Every Strix scan org-wide has been failing closed with a 400 since Strix
moved to contextual-orchestrator's orchestrator/free pool today (#1434):
strix-agent 1.5.3 hardcodes stream_options.include_usage=true for every
turn with no way to disable just that flag, and contextual-orchestrator's
/v1/chat/completions unconditionally rejects that flag whenever tools are
present -- which every Strix turn has.

LLM_DISABLE_STREAMING=true is a genuine, documented strix env var that
makes every turn a single non-streaming call, so stream_options is never
sent and the rejection never fires. This restores the required Strix gate
immediately at the cost of real-time SSE streaming.

This is a temporary mitigation, not the fix: the honest usage-reporting
path contextual-orchestrator's rejection guards against already works
today for non-streaming tool-loop calls (confirmed by reading orchestrator.py
and server.py directly) -- the rejection is a stale, factually-incorrect
defensive check shipped alongside an unrelated fix. Tracking issue #1446
records what must land in contextual-orchestrator before this line is
reverted.

Full suite: 1903 passed, 1 skipped (unchanged from before this commit).
Strix-specific contract tests: 68 passed.
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 8 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d729ef61-1f69-494f-87b2-36f0227350c7

📥 Commits

Reviewing files that changed from the base of the PR and between 8b3235d and 5825560.

📒 Files selected for processing (1)
  • .github/workflows/strix.yml

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Devin Review

# tool-loop stream+include_usage rejection -- the honest usage-reporting
# path it guards already works today for non-streaming tool-loop calls)
# is merged and deployed. Tracking: #1446.
LLM_DISABLE_STREAMING: "true"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Streaming mitigation never reaches Strix

The quick gate omits LLM_DISABLE_STREAMING from its scanner environment, so streaming stays enabled. Gateway requests still fail with 400 responses.

Prompt for agents
The Run Strix workflow sets LLM_DISABLE_STREAMING=true, but scripts/ci/strix_quick_gate.sh creates child_env from an explicit allowlist before launching the Strix executable. That allowlist includes STRIX_REASONING_EFFORT and STRIX_LLM_MAX_RETRIES but not LLM_DISABLE_STREAMING, so the new setting is discarded. Propagate this setting through the trusted child-environment boundary and add a regression test proving the launched scanner receives it while unrelated environment variables remain excluded.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

# tool-loop stream+include_usage rejection -- the honest usage-reporting
# path it guards already works today for non-streaming tool-loop calls)
# is merged and deployed. Tracking: #1446.
LLM_DISABLE_STREAMING: "true"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Upstream switch preserves scan processing

Strix 1.5.3 uses _NonStreamingModel for this setting. It makes one non-streaming request, then replays the result through the normal run loop.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Closing in favor of #1448, which does the same mitigation (LLM_DISABLE_STREAMING=true for Strix) but scoped only to when the resolved LLM_API_BASE is the contextual-orchestrator loopback — this PR sets it unconditionally in the job env, which would also disable streaming for the NVIDIA NIM/OpenRouter/GitHub Models/OpenAI/Vertex/Gemini fallback chain if Strix ever falls back to one of those, losing real-time output there for no reason.

Both PRs are explicitly temporary mitigations for the same root cause — see the note on #1448 for why the real fix (contextual-orchestrator#925, already up for genuine review, not a bypass) is likely to make either of these unnecessary shortly.


Generated by Claude Code


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Good catch, thanks — pushed 346c01ec. scripts/ci/strix_quick_gate.sh builds the actual Strix child process's environment from an explicit allowlist (child_env = {} + a fixed list of forwarded keys), separate from the job-level env: block this PR originally only touched. Without adding LLM_DISABLE_STREAMING to that allowlist, the workflow-level env var never reached the strix executable and the mitigation would have been a no-op.

Added it to the allowlist next to STRIX_REASONING_EFFORT/STRIX_LLM_MAX_RETRIES, and extended the existing runtime-env-forwarding scenario in scripts/ci/test_strix_quick_gate.sh (fake-executable child-env capture) to assert it's actually forwarded. Full test_strix_quick_gate.sh suite: exit 0.


Generated by Claude Code

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.

2 participants