fix(xai): accept Grok Build code during loopback wait + tiny screenshot guard
xAI's consent page renders the authorization code in-page instead of redirecting to the loopback callback, so the listener just hangs and the manual-paste flow demands a callback URL that never contains the token. - auth.py: poll stdin non-blockingly while waiting for the xAI loopback callback; accept a pasted bare Grok Build code and substitute the locally generated state (PKCE code_verifier still binds the exchange). No need to wait for timeout or re-run with --manual-paste. - computer_use: parse PNG/JPEG dimensions from base64 and fall back to the text/AX/SOM payload when the screenshot is below the provider minimum (8x8), which xAI rejects with HTTP 400. - model_setup_flows.py: xAI credential reuse prompt uses the standard radio picker via a shared _prompt_auth_credentials_choice helper. - main.py: thread a title through _prompt_provider_choice; re-home the helper import (flows live in model_setup_flows.py post-decomposition). Salvaged from #36781 onto current main (contributor's main.py edits re-homed to model_setup_flows.py, where the flows were extracted since the PR opened).
This commit is contained in:
@@ -465,7 +465,7 @@ def test_xai_loopback_login_manual_paste_missing_code_raises(monkeypatch):
|
||||
|
||||
|
||||
def test_xai_loopback_login_timeout_falls_back_to_manual_paste(monkeypatch):
|
||||
"""Loopback timeout should offer the existing manual-paste path."""
|
||||
"""Loopback timeout should accept a bare Grok Build code paste."""
|
||||
monkeypatch.setattr(
|
||||
auth_mod, "_xai_oauth_discovery",
|
||||
lambda *_a, **_k: {
|
||||
@@ -523,7 +523,7 @@ def test_xai_loopback_login_timeout_falls_back_to_manual_paste(monkeypatch):
|
||||
captured["prompt_calls"] += 1
|
||||
return {
|
||||
"code": "manual-auth-code",
|
||||
"state": captured["state"],
|
||||
"state": None,
|
||||
"error": None,
|
||||
"error_description": None,
|
||||
}
|
||||
@@ -558,6 +558,48 @@ def test_xai_loopback_login_timeout_falls_back_to_manual_paste(monkeypatch):
|
||||
assert creds["tokens"]["refresh_token"] == "rt-timeout"
|
||||
|
||||
|
||||
def test_xai_wait_for_callback_accepts_ready_stdin_code(monkeypatch):
|
||||
"""Users can paste the Grok Build code while Hermes is still waiting."""
|
||||
class _StubServer:
|
||||
shutdown_called = False
|
||||
close_called = False
|
||||
|
||||
def shutdown(self):
|
||||
self.shutdown_called = True
|
||||
|
||||
def server_close(self):
|
||||
self.close_called = True
|
||||
|
||||
class _StubThread:
|
||||
joined = False
|
||||
|
||||
def join(self, timeout=None):
|
||||
self.joined = True
|
||||
|
||||
server = _StubServer()
|
||||
thread = _StubThread()
|
||||
monkeypatch.setattr(
|
||||
auth_mod,
|
||||
"_read_ready_stdin_line",
|
||||
lambda: "ready-grok-build-code\n",
|
||||
)
|
||||
|
||||
out = auth_mod._xai_wait_for_callback(
|
||||
server,
|
||||
thread,
|
||||
{"code": None, "error": None},
|
||||
timeout_seconds=5,
|
||||
manual_paste_redirect_uri="http://127.0.0.1:56121/callback",
|
||||
)
|
||||
|
||||
assert out["code"] == "ready-grok-build-code"
|
||||
assert out["state"] is None
|
||||
assert out["_manual_paste"] is True
|
||||
assert server.shutdown_called is True
|
||||
assert server.close_called is True
|
||||
assert thread.joined is True
|
||||
|
||||
|
||||
def test_xai_loopback_login_timeout_noninteractive_reraises(monkeypatch):
|
||||
"""Non-interactive stdin must keep the original timeout error."""
|
||||
monkeypatch.setattr(
|
||||
|
||||
Reference in New Issue
Block a user