fix: GPT session re-auth crash + cleaner ImplementAndJudge card - #181
Conversation
When OAuth refresh blanks the live client's api_key mid-session, the OpenAI SDK raises a bare TypeError that bypassed error handlers. Map that case to APIStatusError(401) so refresh and /login recovery can engage.
Add a dedicated tool renderer so the chain shows "Implement & Judge — <brief>" instead of a raw argument dump. Document unreleased auth-recovery and TUI fixes.
📝 WalkthroughWalkthroughTwo independent fixes: ChangesOpenAI Session Token 401 Fix
ImplementAndJudge TUI Renderer
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/pythinker-core/tests/test_openai_responses_auth.py`:
- Around line 20-21: Add the `@pytest.mark.asyncio` marker to both async test
functions in the file. The functions `test_blanked_credential_raises_typed_401`
and `test_typeerror_with_valid_key_propagates` are defined as `async def` but
lack the required marker. Since the project does not configure `asyncio_mode =
"auto"` in pytest configuration, these async functions will not be properly
awaited by pytest and will silently pass without executing their assertions.
Place `@pytest.mark.asyncio` on a new line immediately before each async
function definition, above any other decorators like `@pytest.mark.parametrize`.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 82f5d8a7-c1fd-42eb-b680-d00470dd2341
📒 Files selected for processing (6)
CHANGELOG.mdpackages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_responses.pypackages/pythinker-core/tests/test_openai_responses_auth.pysrc/pythinker_code/ui/shell/tool_renderers/__init__.pysrc/pythinker_code/ui/shell/tool_renderers/implement_judge.pytests/ui_and_conv/test_tui_card_tool_renderers.py
|
All findings triaged on head
No code changes required. |
Summary
Two independent, small fixes (one commit each).
1.
fix(core): GPT/ChatGPT mid-session credential crash → typed 401When a ChatGPT (
openai_codex) session token is invalidated mid-session — classically because the same OAuth credentials were reused on another machine, rotating the single-use refresh token so this machine's refresh is rejected —OAuthManager._apply_access_token(runtime, ref, "")blanks the live OpenAI client'sapi_keyto"". The client was already constructed with a valid token, so this slips past the SDK's construction-time credential check and the nextresponses.createraises a bareTypeErrorfrom_validate_headers("Could not resolve authentication method…"). ThatTypeErroris neitherOpenAIErrornorhttpx.HTTPError, so it escaped the provider and the soul's 401/connection recovery and surfaced as a fatal "Unexpected error".The provider now converts that unresolved-credential
TypeErrorinto a typedAPIStatusError(401)(gated onnot self._client.api_key, so unrelatedTypeErrors still propagate).APIStatusErrorsubclassesChatProviderError, so it routes into the existing refresh → re-auth path and the shell's "Type /login to re-authenticate" message instead of crashing.Reproduced end-to-end (identical
TypeError); fix verified for bothstream=Trueandstream=False(the SDK raises at request-build time, sogenerate()catches both).Out of scope (noted, not changed here):
_apply_access_token(runtime, ref, "")discards a possibly-still-valid access token just because the refresh token died — a separate token-lifecycle change.2.
fix(tui): cleanerImplementAndJudgecardThe
ImplementAndJudgechain tool had no dedicated renderer, so it fell back to the genericImplementAndJudge(4 args: acceptance, base_prompt, brief, scope)arg dump. Added a dedicated renderer:Internal tool name stays
ImplementAndJudge(registry/config/tests unchanged); only the on-screen label changes. Thejudgesubagent name was already consistent across specs/profiles/docs — no naming changes needed.Tests
packages/pythinker-core/tests/test_openai_responses_auth.py: blanked-credential →APIStatusError(401)for both stream modes; negative case (TypeError with non-empty key still propagates).tests/ui_and_conv/test_tui_card_tool_renderers.py: clean label + brief, no arg dump; running state; a name-sync invariant so a rename can't silently fall back to the generic renderer.Verification
make check-pythinker-core✅ ·make check-pythinker-code✅ (ruff + format + pyright + ty) · pythinker-core suite 305 passed · TUI renderer suite 157 passed.Summary by CodeRabbit
Release Notes
Bug Fixes
UI Improvements