Skip to content

fix(agent): route MoA streaming through virtual client - #57328

Closed
deaneeth wants to merge 2 commits into
NousResearch:mainfrom
deaneeth:fix/fix-moa-streaming-provider
Closed

fix(agent): route MoA streaming through virtual client#57328
deaneeth wants to merge 2 commits into
NousResearch:mainfrom
deaneeth:fix/fix-moa-streaming-provider

Conversation

@deaneeth

@deaneeth deaneeth commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Routes MoA streaming requests through the existing in-process MoA client facade instead of constructing a request-local OpenAI client for the virtual moa://local endpoint.

Root cause: interruptible_streaming_api_call() always used _create_request_openai_client() for chat-completions streaming. That is correct for real OpenAI-compatible endpoints, but MoA is a virtual provider backed by agent.client.chat.completions.create(...). Gateway platforms using streaming therefore tried to connect to moa://local and failed with APIConnectionError.

Related Issue

Fixes #57251

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Tests (adding or improving test coverage)

Changes Made

  • agent/chat_completion_helpers.py: use agent.client.chat.completions.create for provider == "moa" in the streaming path while preserving existing streaming assembly, timeout, diagnostics, fallback behavior, and interrupt/stale stream teardown.
  • tests/run_agent/test_streaming.py: add regression coverage proving MoA streaming does not create a request OpenAI client, still forwards stream=True / stream_options to the MoA facade, and closes a hung MoA stream handle on interrupt.

How to Test

  1. python -m pytest tests/run_agent/test_streaming.py -q
  2. python -m pytest tests/run_agent/test_moa_streaming.py tests/agent/test_moa_trace_streamed_capture.py -q
  3. python scripts/run_tests_parallel.py tests/run_agent/test_streaming.py tests/run_agent/test_moa_streaming.py tests/agent/test_moa_trace_streamed_capture.py -q
  4. python -m ruff check agent/chat_completion_helpers.py tests/run_agent/test_streaming.py

Local result:

  • tests/run_agent/test_streaming.py: 44 passed, 2 skipped
  • tests/run_agent/test_moa_streaming.py + tests/agent/test_moa_trace_streamed_capture.py: 12 passed
  • scripts/run_tests_parallel.py ...: 55 passed, 0 failed
  • ruff check ...: all checks passed

Checklist

Code

  • I read the Contributing Guide
  • My commit message follows Conventional Commits
  • I searched for existing PRs to make sure this is not a duplicate
  • My PR contains only changes related to this fix
  • I added tests for my changes
  • I tested on my platform: Windows 11 / Python 3.11.15

Documentation & Housekeeping

  • Documentation update N/A
  • cli-config.yaml.example update N/A
  • CONTRIBUTING.md / AGENTS.md update N/A
  • Cross-platform impact considered: change is provider dispatch only, no OS-specific behavior
  • Tool descriptions/schemas update N/A

Copilot AI review requested due to automatic review settings July 2, 2026 20:15

Copilot AI 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.

Pull request overview

This PR fixes MoA (“moa://local”) streaming on gateway platforms by routing streaming chat-completions through the existing in-process MoA client facade (agent.client) rather than constructing a request-scoped OpenAI client that attempts to connect to the virtual moa://local URL.

Changes:

  • Update the streaming chat-completions path to call agent.client.chat.completions.create(...) when provider == "moa", preserving existing stream assembly/diagnostics behavior for other providers.
  • Add regression tests ensuring MoA streaming does not create a request OpenAI client and still forwards stream=True and stream_options.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
agent/chat_completion_helpers.py Adds a MoA-specific dispatch in the streaming chat-completions path to use the in-process MoA client facade.
tests/run_agent/test_streaming.py Adds/updates tests to assert MoA streaming bypasses request OpenAI client creation and preserves streaming kwargs forwarding.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread agent/chat_completion_helpers.py
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have labels Jul 2, 2026
@teknium1

teknium1 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Thanks for the clean writeup and tests, @deaneeth — this is a well-constructed PR. Closing it because the bug it targets is already fixed on current main, via a different mechanism.

Since ~June 27 (66aeda355, PR #53826 "keep virtual provider on MoA client"), AIAgent._create_request_openai_client() short-circuits for the MoA virtual provider:

def _create_request_openai_client(self, *, reason, api_kwargs=None):
    primary_client = self._ensure_primary_openai_client(reason=reason)
    if self.provider == "moa":
        return primary_client   # <- the MoA facade itself
    ...

So the streaming path's request_client.chat.completions.create(stream=True, ...) already lands on MoAChatCompletions.create() — no OpenAI client is ever constructed against moa://local. The MoA streaming feature (PR #55625) explicitly relies on this routing (see the comment at agent/conversation_loop.py ~L1201).

Verified end-to-end on current main with the client factory unmocked: a provider="moa" agent's _interruptible_streaming_api_call() dispatched to the facade with stream=True and stream_options={"include_usage": True} and assembled the streamed response correctly.

The reproduction in #57251 is from a build predating June 27 — hermes update resolves it.

The one adjacent observation worth keeping: on interrupt of a hung MoA stream, the abort path targets the facade (which has no sockets), so stream-handle teardown there is a genuine but separate gap from what this PR/issue reported. If you want to pursue that as its own focused PR against current main, it would be welcome.

Appreciate the contribution and the regression tests — sorry this one collided with an already-landed fix.

@deaneeth

deaneeth commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@teknium1 Confirmed after checking latest main: the routing bug this PR targeted was already fixed via #53826, so closing this PR was the right call.

I split out only the separate MoA stream-handle teardown gap you mentioned into a focused PR: #57354 . It keeps current main’s MoA facade routing intact and only adds interrupt/stale cleanup for the active per-request MoA stream handle.

Thank you so much for pointing that out, when you have a time please take a look...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MoA streaming: APIConnectionError on gateway platforms (missing provider branch)

4 participants