ab879a1e22
`_moa_prepared_request` is a private handshake between the conversation
loop and MoAChatCompletions.create. It is attached whenever
agent.provider == "moa", on the assumption that agent.client is still the
in-process MoA facade.
Credential rotation, provider fallback and dead-connection cleanup all
rebuild agent.client from _client_kwargs between attempts, and
pending_moa_prepared_request deliberately carries a prepared request
across exactly that boundary. The rebuilt client is a native OpenAI
client while provider stays "moa", so the key reaches an SDK that has
never heard of it:
TypeError: Completions.create() got an unexpected keyword argument
'_moa_prepared_request'
That error is non-retryable, so every remaining turn on the session
fails. Both dispatch paths are affected: the non-streaming one calls
agent.client directly, and _create_request_openai_client returns
agent.client unchanged for provider "moa".
Re-check the live client at the point the key is attached, which covers
both paths at once. When the facade is gone, send the prepared prompt
without the handshake and log the downgrade.
63 lines
2.3 KiB
Python
63 lines
2.3 KiB
Python
"""`_moa_prepared_request` must never reach a client that cannot consume it.
|
|
|
|
The key is a private handshake between the conversation loop and
|
|
``MoAChatCompletions.create``. Credential rotation, provider fallback and
|
|
dead-connection cleanup rebuild ``agent.client`` from ``_client_kwargs``
|
|
between attempts — and a prepared request survives that boundary via
|
|
``pending_moa_prepared_request`` — while ``agent.provider`` stays ``"moa"``.
|
|
Handing the key to the rebuilt native client raises a non-retryable
|
|
``TypeError`` that kills every remaining turn on the session.
|
|
"""
|
|
|
|
import types
|
|
|
|
from agent.conversation_loop import _moa_client_consumes_prepared_request
|
|
from agent.moa_loop import MoAChatCompletions
|
|
|
|
|
|
def _client_with(completions):
|
|
return types.SimpleNamespace(
|
|
chat=types.SimpleNamespace(completions=completions)
|
|
)
|
|
|
|
|
|
class _NativeCompletions:
|
|
"""openai.resources.chat.Completions — an explicit keyword signature."""
|
|
|
|
def create(self, *, model=None, messages=None, tools=None, stream=None):
|
|
return "native ok"
|
|
|
|
|
|
def test_native_client_does_not_consume_the_prepared_request():
|
|
assert _moa_client_consumes_prepared_request(_client_with(_NativeCompletions())) is False
|
|
|
|
|
|
def test_real_moa_facade_consumes_the_prepared_request():
|
|
facade = MoAChatCompletions.__new__(MoAChatCompletions)
|
|
assert _moa_client_consumes_prepared_request(_client_with(facade)) is True
|
|
|
|
|
|
def test_client_without_a_chat_attribute_is_not_a_facade():
|
|
assert _moa_client_consumes_prepared_request(object()) is False
|
|
assert _moa_client_consumes_prepared_request(None) is False
|
|
|
|
|
|
def test_native_client_rejects_the_key_it_must_not_receive():
|
|
"""Why the guard exists: the kwarg is fatal to a native client."""
|
|
native = _NativeCompletions()
|
|
try:
|
|
native.create(
|
|
model="2 model",
|
|
messages=[{"role": "user", "content": "hi"}],
|
|
_moa_prepared_request={"messages": [], "layers": 3},
|
|
)
|
|
except TypeError as exc:
|
|
assert "_moa_prepared_request" in str(exc)
|
|
else: # pragma: no cover - would mean the premise no longer holds
|
|
raise AssertionError("native client accepted the private MoA kwarg")
|
|
|
|
# Without the key it is an ordinary call the rebuilt client can serve.
|
|
assert native.create(
|
|
model="2 model", messages=[{"role": "user", "content": "hi"}]
|
|
) == "native ok"
|