Skip to content

Studio: persistent stdio MCP sessions so server state survives across tool calls - #7080

Merged
danielhanchen merged 21 commits into
unslothai:mainfrom
NilayYadav:fix-mcp-persistent-stdio-sessions
Jul 14, 2026
Merged

danielhanchen merged 21 commits into
unslothai:mainfrom
NilayYadav:fix-mcp-persistent-stdio-sessions

Conversation

@NilayYadav

@NilayYadav NilayYadav commented Jul 11, 2026 •

Copy link
Copy Markdown
Collaborator

call_tool_sync spawned a fresh stdio subprocess for every MCP tool call (StdioTransport(keep_alive=False)) and tore it down when the call returned so any stateful stdio server lost its state between calls.

With @playwright/mcp this means:

  1. browser_navigate spawns a server, opens the page, returns > subprocess and
    browser destroyed
  2. browser_take_screenshot spawns a brand-new server > fresh browser at
    about:blank > screenshots an empty page

There's no error, the tool returns a perfectly valid result for a blank page, so it just looks like the feature is broken. The same applies to any server holding live state (DB sessions, REPLs, terminal servers). Only stateless servers (filesystem, fetch) worked.

Fix

Keep one connected client per (command, env, chat session) on a dedicated event-loop thread and reuse it across tool calls.

  • No orphan processes: idle sessions are reaped after 5 minutes (in-flight calls excluded), sessions close on server update/delete, and an atexit hook closes everything at shutdown.
  • Per-conversation isolation: the session key includes the chat's session_id, so one conversation's browser/DB state never leaks into another.
  • Crash recovery: a dead subprocess is detected via is_connected() and the call retried once on a fresh session; tool-level errors leave the session up.
  • No head-of-line blocking: per-key locks, so a slow npx startup for one server doesn't block calls to any other.
  • Timeout/cancel semantics preserved: /cancel interrupts during connect and during the call; timeout=None (no limit) stays unlimited; a timed-out call does not tear the session down.
  • HTTP/SSE servers are unchanged (still one-shot per call).

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces persistent stdio sessions for MCP servers to preserve server-side state across tool calls, managing connected clients on dedicated event-loop threads with idle reaping and cancellation support. The review feedback suggests two key improvements: first, avoiding head-of-line blocking by releasing the global lock during slow network operations like session connection and closure; second, making the session teardown path more robust by defensively accessing attributes to handle partially-constructed objects.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread studio/backend/core/inference/mcp_client.py Outdated
Comment thread studio/backend/core/inference/mcp_client.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 024467b5ce

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/mcp_client.py Outdated
Comment thread studio/backend/core/inference/mcp_client.py Outdated
Comment thread studio/backend/core/inference/mcp_client.py Outdated
@NilayYadav NilayYadav closed this Jul 11, 2026
@NilayYadav
NilayYadav deleted the fix-mcp-persistent-stdio-sessions branch July 11, 2026 17:17
@NilayYadav NilayYadav changed the title Studio: persistent stdio MCP sessions so server state survives across tool calls Withdrawn Jul 11, 2026
@NilayYadav NilayYadav changed the title Withdrawn Studio: persistent stdio MCP sessions so server state survives across tool calls Jul 11, 2026
@NilayYadav
NilayYadav restored the fix-mcp-persistent-stdio-sessions branch July 11, 2026 17:25
@NilayYadav NilayYadav reopened this Jul 11, 2026
… tool calls

call_tool_sync spawned a fresh stdio subprocess per tool call
(keep_alive=False) and tore it down when the call returned, so any stateful
MCP server lost its state between calls: with @playwright/mcp,
browser_navigate opened the page in one subprocess and
browser_take_screenshot ran in a brand-new one, screenshotting about:blank.

Keep one connected client per (command, env) on a dedicated event-loop
thread and reuse it across calls:

- idle sessions are reaped after 5 minutes (in-flight calls excluded) and
  everything closes at exit, preserving the old design's no-orphans property
- a dead subprocess is detected via is_connected() and retried once on a
  fresh session; tool-level errors leave the session alone
- cancel and timeout semantics are unchanged, and a timed-out call does not
  tear the session down
- updating a server's endpoint/env/enabled state or deleting it closes its
  live session
- HTTP/SSE servers stay one-shot per call
@NilayYadav
NilayYadav force-pushed the fix-mcp-persistent-stdio-sessions branch from 024467b to a1b67e6 Compare July 11, 2026 17:27
@NilayYadav

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b873136a92

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/mcp_client.py Outdated
Comment thread studio/backend/core/inference/mcp_client.py
Comment thread studio/backend/core/inference/mcp_client.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0edede3129

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/tools.py Outdated
Comment thread studio/backend/core/inference/mcp_client.py Outdated
Comment thread studio/backend/core/inference/mcp_client.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eb04379390

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/mcp_client.py Outdated
Comment thread studio/backend/core/inference/mcp_client.py
Comment thread studio/backend/core/inference/mcp_client.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 05588eeb09

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/mcp_client.py Outdated
Comment thread studio/backend/core/inference/mcp_client.py Outdated
Comment thread studio/backend/core/inference/mcp_client.py
…efore caching, keep env secrets out of generation keys

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bc16dfdbcc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/mcp_client.py
Comment thread studio/backend/core/inference/mcp_client.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a6767219d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/tools.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a29e973f42

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/mcp_client.py
Comment thread studio/backend/core/inference/mcp_client.py Outdated
Comment thread studio/backend/core/inference/mcp_client.py Outdated
Comment thread studio/frontend/src/features/chat/api/chat-adapter.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b2154cae4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +493 to +495
session = _checkout_stdio_session(key)
if session is not None:
return session

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Revalidate cached stdio sessions before reuse

When a request has already read the old MCP server row and then an update/delete changes that row before close_stdio_sessions() has removed the cached entry, this cached-session fast path returns without calling config_check. In that race the tool can still run on a disabled, deleted, or repointed stdio server; fresh connects are rechecked later, but cache hits bypass that protection. Check the current row before returning a cached session, or make the close/remove step happen before stale callers can borrow it.

Useful? React with 👍 / 👎.

for key in expired:
_discard_stdio_key_lock(key)
for session in sessions:
logger.info("Closing idle stdio MCP session: %s", session.url)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Redact raw stdio commands in idle logs

When a stdio MCP command embeds credentials in argv (for example npx server --token ...), the idle reaper writes the full command to INFO logs every time that session ages out. The same code already treats command URLs as potentially secret when hashing generation keys, so this log can persist deleted API keys or bearer tokens outside the MCP config; log a server id/digest or a redacted command instead.

Useful? React with 👍 / 👎.

danielhanchen and others added 2 commits July 12, 2026 11:56
…oping

- Evict a stdio session on any transport-level (non-ToolError) call failure and
  do not replay it, so a mid-call subprocess crash can no longer poison the scope.
  Never gate liveness on Client.is_connected() (it only reports that a session
  object exists, not that the subprocess is alive); add a version-adaptive
  dead-transport probe that works on fastmcp 3.0.2 and newer.
- Re-check closed/defunct/config and transport liveness after acquiring the call
  lock, and retire a session before releasing the lock, so a queued same-scope
  caller never reuses a session that another caller's timeout already retired.
- Force a ProactorEventLoop on Windows so the stdio transport can always spawn
  subprocesses regardless of the active event-loop policy.
- Scope stdio sessions per conversation: require thread_id to persist, and tag
  the fields so a session_id and a thread_id with the same value cannot collide.
  A session_id alone is project-wide, so it now falls back to a safe one-shot
  session instead of sharing browser/DB/REPL state across conversations.
- Forward thread_id on the Anthropic Messages path.
- Treat timeout=None as unlimited on connect and the key lock (was capped at 60s).
- Bound the session cache (default 32, override via
  UNSLOTH_STUDIO_MAX_STDIO_MCP_SESSIONS) with LRU eviction of idle sessions.
- Run config_check on cache hits, and log a redacted exe#digest label instead of
  the raw command so credentials in argv never reach the logs.
@danielhanchen

Copy link
Copy Markdown
Member

Pushed a commit that hardens the persistent stdio session lifecycle. The persistence design is the right call, this just closes the recovery, concurrency, and isolation gaps around it.

Crash recovery (main one)
A mid-call subprocess crash used to leave the dead session cached and never retried, because Client.is_connected() only reports that a session object exists, not that the subprocess is alive. Now any transport-level call failure (anything that is not a ToolError) evicts the session so it cannot poison the scope, and we do not replay the call, since the tool may already have run and replaying a mutating tool would double-execute. A version-adaptive dead-transport probe reconnects safely when the death is detected before dispatch. Works on fastmcp 3.0.2 and newer.

Queued-borrower race
A caller waiting on the per-session call lock could reuse a session that another caller's timeout had just retired, running two operations on one stateful client. We now re-check closed/defunct/config and transport liveness after acquiring the lock, and retire a session before releasing the lock so the next borrower moves to a fresh one.

Windows event loop
The session thread forces a ProactorEventLoop on win32 so the stdio transport can always spawn subprocesses regardless of the active event-loop policy.

Scope isolation
session_id is the project-wide sandbox id shared by every thread in a project, so scoping by it alone leaked browser/DB/REPL state across conversations. Persistence now requires a thread_id, and the scope fields are tagged (s=...:t=...) so a session_id and a thread_id with the same value cannot collide. A session_id alone falls back to a safe one-shot session. The Anthropic Messages path now forwards thread_id too.

Smaller items

  • timeout=None is unlimited on connect and the key lock (was capped at 60s).
  • The session cache is bounded (default 32, override via UNSLOTH_STUDIO_MAX_STDIO_MCP_SESSIONS) with LRU eviction of idle sessions.
  • config_check runs on cache hits, and logs use a redacted exe#digest label instead of the raw command so credentials in argv never reach the logs.

Verification

  • The session suite plus a simulation suite (persistence/isolation, mid-call crash recovery with no scope poisoning, replay safety, the borrower race, scope collision, uncapped timeout=None, cache cap, config revalidation, redacted logging) are green on fastmcp 3.4.4 and the declared minimum 3.0.2.
  • Real-subprocess persistence, one-shot fallback, and mid-call crash recovery run green on ubuntu-latest, macos-14, and windows-latest, so the Windows Proactor path and the command-line round-trip are exercised natively.
  • Real browser end to end via @playwright/mcp on Chromium, Firefox, and WebKit: state persists on the same scope and a different scope gets a fresh context.

No schema change, no migration, and no new dependency, so existing installs update safely, and all new parameters are optional so an older frontend just falls back to one-shot.

@danielhanchen

Copy link
Copy Markdown
Member

Ran this fix end to end in the actual Studio chat UI with Playwright, before and after the PR, on GPU-less GitHub CI runners. A stateful stdio MCP increment server returns its in-memory counter and its process id; a local tool-capable model calls it twice in one conversation.

before and after, side by side

animated before and after

1st call 2nd call (same conversation) Server process
Before (merge-base 9fa6fd40e) COUNTER=1 COUNTER=1 different PID, state lost
After (this PR) COUNTER=1 COUNTER=2 same PID, state kept
After, new conversation COUNTER=1 - new PID, isolated

The raw tool-result cards are the oracle here (a small model can paraphrase the number in its prose). Before the PR every stdio tool call spawns and tears down a fresh subprocess, so a stateful stdio server (browser, DB, REPL) loses all state between calls. After the PR, calls that share a conversation reuse one persistent process, and a new conversation still gets a fresh isolated one. Both turns in a conversation carry one stable thread_id; a new conversation gets a different thread_id.

Cross-platform backend tests, the session suite plus a real-subprocess persistence and mid-call-crash test, pass fail-hard on ubuntu-latest, macos-14, and windows-latest, including the Windows ProactorEventLoop path and the list2cmdline round-trip.

danielhanchen and others added 2 commits July 13, 2026 01:40
… for HTTP servers

Two fixes from review of the persistent stdio session lifecycle:

- Re-enforce the session cap when a session goes idle. A concurrent burst of
  distinct-scope calls can overshoot the cap while every cached session is busy
  (insert-time eviction only reclaims idle sessions), and the overshoot used to
  persist until the 5-minute idle reaper. _release_stdio_session now trims the
  idle overshoot back within the cap, without ever evicting an in-flight call.
- close_stdio_sessions() now no-ops for a specific non-stdio (HTTP/SSE) url.
  Those transports are never cached as stdio sessions, so calling it on every
  HTTP server update or delete used to accrue an unbounded close-generation entry.

Both are covered by regression tests that fail before the change and pass after.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 38dbf785a1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +896 to +899
ephemeral = not scope
if ephemeral:
scope = f"request-{uuid.uuid4().hex}"
key = _session_key(url, headers, scope)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep one-shot stdio calls out of the shared cache

When thread_id/scope is absent, this creates a unique scope but still sends the call through _get_stdio_session, which publishes the session into _stdio_sessions and runs LRU eviction before the tool executes. If the cache is full of idle persistent chat sessions, a one-shot request can evict an unrelated chat's browser/REPL session and then immediately drop its own ephemeral session in finally, so the other chat loses the state this feature is meant to preserve. Use a private uncached session for ephemeral calls, or at least skip LRU eviction/insertion for them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One-shot calls (no thread_id) already run under a unique per-request scope (request-) and are dropped immediately after the single call, so they never share a process or state with a conversation. Holding one cache slot for the duration of that single call is intentional; stdio MCP is single-user loopback, so cache contention is not a concern.

Comment on lines +589 to +592
session.connect(
None if deadline is None else max(0.0, deadline - time.monotonic()),
cancel_event,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reserve stdio capacity before spawning sessions

This starts connecting the new stdio session before any cache-cap check, and connecting sessions are not counted in _stdio_sessions. A burst of first calls with distinct thread_id values can therefore spawn far more than _STDIO_MAX_SESSIONS subprocesses/loop threads while they are still starting; if those calls remain in flight, the later LRU eviction also skips them, so the configured cap does not protect against the resource-exhaustion case it was added for. Reserve/queue against the cap before creating and connecting the session.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The cap is a soft cap by design: eviction only reclaims idle sessions and never kills an in-flight connect, so a burst can transiently overshoot rather than drop a live call. The overshoot is reclaimed as sessions go idle via the release-time trim, covered by test_stdio_cache_trims_overshoot_after_burst.

@danielhanchen

Copy link
Copy Markdown
Member

Did another pass over the stdio session lifecycle. Pushed two fixes in d745b79 and intentionally left the rest, with reasoning below.

Fixed

  • Re-enforce the session cap when a session goes idle. A concurrent burst of distinct-scope calls can overshoot the cap while every cached session is busy (insert-time eviction only reclaims idle sessions), and the overshoot used to persist until the 5-minute idle reaper. _release_stdio_session now trims the idle overshoot back within the cap, without ever evicting an in-flight call.
  • close_stdio_sessions() now no-ops for a specific non-stdio (HTTP/SSE) url. Those transports are never cached as stdio sessions, so calling it on every HTTP server update or delete used to accrue an unbounded close-generation entry.

Both have regression tests that fail before the change and pass after.

Considered and left as is

  • Windows event loop on Python 3.13: asyncio.ProactorEventLoop (the loop class) is available and not deprecated in 3.13 or 3.14. Only WindowsProactorEventLoopPolicy (the policy) is deprecated, with removal planned for 3.16, so the current direct construction is the future-proof form.
  • Timeout or cancel discarding the session: intentional. Cancellation is cooperative, so the cancelled call may still be running on the transport; returning that client to the cache could interleave with the next call.
  • The 60s connect cap: it guards against a wedged first connect. Removing it would let the default path wait the entire call timeout on a stuck startup.
  • Adding server_id to the session identity: this only affects two rows configured with an identical command and environment. Sharing one process for identical commands is intentional deduplication.
  • thread_id as an isolation boundary: stdio MCP is gated to single-user loopback, so there is no cross-user impersonation surface here.
  • First-turn thread_id on remount: this is frontend only and does not affect the backend session lifecycle. Better handled as its own change.

Cross-platform backend tests remain green on ubuntu-latest, macos-14, and windows-latest.

danielhanchen and others added 2 commits July 13, 2026 10:23
The edit dialog resends url, headers, and use_oauth unchanged whenever a
server is saved, so gating the tool-cache invalidation and stdio session
close on field presence dropped the persistent process on a plain rename
or any no-op edit. Gate on a real value change against the stored row so
only a genuine endpoint, auth, or enable change closes the session.

Regression tests: a rename that resends unchanged url/headers/oauth keeps
the session; a real command change still closes it.
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 99674c6e5b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Collapse a few verbose comments to fewer lines with the wording preserved,
and drop one that restated the clear_oauth_tokens_async docstring. Comments
only; no code change.
@unslothai unslothai deleted a comment from chatgpt-codex-connector Bot Jul 14, 2026
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 3a195492ae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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