fix(grok): health check, model selection, and stop all work against the real CLI - #9154

Merged
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support
Sep 2, 2026
Merged

fix(grok): health check, model selection, and stop all work against the real CLI#9154
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Grok Build had a cluster of reliability problems that made it feel broken even when the CLI itself was fine:

  • The provider health check opened a full ACP session. authenticate could launch a browser login on its own, and session/new booted every configured MCP server, so background checks hung, timed out, and persisted error over a working install. It also never reported auth state.
  • Picking the built-in Grok Build model failed with unknown model id, because grok-build is the CLI's product name, not a model id its ACP accepts.
  • Stop did not stop. The next message queued behind the old prompt, which kept running to completion.
  • Mid-turn sends queued instead of interrupting like Claude and Codex.

What changed

Health check without a session.grok --version, then grok models for login state and slugs, then a single ACP initialize and reads models from _meta.modelState. No authenticate, no session/new. A failed initialize degrades to warning with the CLI's model list instead of error. XAI_API_KEY counts as authenticated. Against Grok CLI 1.0.13 this returns ready, authenticated, and both models with reasoning options in about 1.2 s.

grok-build means "the session's current model". It is never sent in session/set_model. No hardcoded alias to rot when the next model ships. The mock agent now advertises versioned ids like the real CLI so this cannot regress silently.

Stop actually cancels. This was the root cause behind both stop issues. effect-acp encoded notifications through the Request path, so session/cancel went out as {"id":"","headers":[]}. Grok CLI parses that as a malformed request and drops it. The mock agent was lenient and hid this. Notifications now serialize with no id. Verified live: Stop then a new send answers the new prompt immediately with nothing leaked from the old one. Before this fix the old prompt's output kept streaming into the new turn.

Mid-turn sends interrupt. Takes over #8286 by @mavenskylab with authorship preserved, plus one follow-up that replaces the eight-yieldNow sync loop with a Deferred the ACP runtime settles once the prompt RPC is registered.

Verification

  • Focused tests for the health check parser, model-state builder, product-slug handling, ACP notification encoding, and the existing Grok, Cursor, and ACP runtime suites. 211 passing.
  • Live against Grok CLI 1.0.13: health check snapshot, and stop-then-resend with wire capture of every frame T3 wrote to the agent.

Closes#7746, #5852, #7505, #6075, #8283, #8461.

Written by Claude Fable 5.1 in Claude Code.


Note

Medium Risk
Shared ACP protocol and cancel timing changes affect all ACP-backed providers, not only Grok; Grok steer adds epoch-based concurrency that must stay consistent with interrupt and settlement paths.

Overview
Fixes Grok reliability by aligning probes and turn control with the real CLI, and repairs ACP session/cancel so Grok (and other agents) actually receive cancellation frames.

Provider health check no longer runs authenticate or session/new. It probes grok --version, parses grok models for login state and slugs, then a short ACP initialize to read models from _meta.modelState. Unauthenticated CLIs error with a login hint; failed initialize degrades to warning with CLI-listed models. XAI_API_KEY overrides CLI login for auth reporting.

Model selection: the built-in grok-build slug is T3’s product name—it is never sent in session/set_model; choosing it keeps the session’s current ACP model (reasoning changes still apply to that model). The mock agent advertises versioned ids like production.

Mid-turn sends (steer) on Grok now session/cancel the in-flight prompt, then send the replacement under a prompt epoch / lifecycle semaphore, so new input interrupts like Claude/Codex instead of queueing behind the old prompt.

effect-acp: outbound notifications encode as proper JSON-RPC (no id or headers); RPC Interrupt control messages are dropped. AcpSessionRuntime.cancel awaits the cancel write before completing; prompt can signal dispatched once the prompt RPC is registered for steer races.

Reviewed by Cursor Bugbot for commit 2b9bde5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix Grok health check, model selection, and concurrent turn steering

  • Rewrites checkGrokProviderStatus to probe via ACP initialize only (no session creation), then fall back to grok models CLI output and built-in models; derives auth state from XAI_API_KEY or CLI login text
  • Treats the grok-build product slug as "keep current session model" in applyGrokAcpModelSelection — it is no longer sent through session/set_model; reasoning changes apply to the resolved current model
  • Reworks GrokAdapter.sendTurn with a prompt epoch and lifecycle semaphore so a concurrent turn cancels the active ACP prompt before starting a replacement, skips superseded prompts, preserves the original prompt when replacement prep fails, and emits exactly one terminal event per turn
  • Encodes outbound ACP notifications through encodeJsonRpcNotification without id or headers, and discards @effect/rpc/Interrupt messages so they are not sent to ACP agents
  • Risk: discoverGrokModelsViaAcpInitialize now sends only initialize — any code relying on session creation during discovery will no longer get it; sendNotification encoding failures now surface as ACP protocol parse errors rather than native TypeErrors

Macroscope summarized 2b9bde5.

mavenskylaband others added 6 commits September 1, 2026 18:10
Sending a follow-up on a Grok thread waited behind the in-flight ACP
prompt instead of interrupting like Claude/Codex. A steer now cancels
the current prompt and continues the same turn immediately.
Usage-limit exhaustion was already fixed on main by #8358.
Fixes#8283
Made by Grok 4.6 via the Grok harness.
Discarded and interrupted prompts settled turn state while holding
the prompt-lifecycle lock, so settlement could race interruptTurn
or the next sendTurn. Skip vs start still happens under that lock;
settlement now waits for the thread lock after the permit is released.
Made by Grok 4.6 via the Grok harness.
A failed empty steer advanced discardBeforeEpoch before the replacement
prompt prepared, so the live prompt skipped ACP and settled without
turn.completed. Discard the previous epoch only after prep succeeds.
Made by Grok 4.6 via the Grok harness.
The steer path forked session/prompt and then yielded eight times, hoping
the runtime had registered the RPC fiber before releasing the lifecycle
lock. The runtime now settles a Deferred once the prompt is the active
fiber, and the adapter waits on that or on prompt failure.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… as a model id
The Grok health check opened a full ACP session: initialize, authenticate,
session/new. authenticate can launch a browser login, and session/new
boots every configured MCP server. Background checks hung, timed out,
and persisted an error over a working install. The success branch also
hard-coded auth unknown.
The check now runs grok --version, then grok models for login state and
slugs, then a single ACP initialize and reads models from
_meta.modelState. A failed initialize degrades to warning with the CLI
list instead of error. XAI_API_KEY counts as authenticated.
grok-build is the CLI product name, not a model id its ACP accepts, so
session/set_model rejected it. It now means keep the session current
model and is never sent over the wire. The mock agent advertises
versioned ids like the real CLI so this cannot regress silently.
Closes#7746, #5852, #7505, #6075.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Notifications went out through the generic Request encoder, which added
id: "" and headers: []. Grok CLI parses that as a malformed request and
drops it, so Stop never reached the agent and the old prompt kept
running after the next send. The mock agent was lenient and hid this.
Notifications now serialize as {jsonrpc, method, params} with no id.
The client also stops emitting @effect/rpc/Interrupt frames, which ACP
agents log as Method not found.
Verified against Grok CLI 1.0.13: Stop cancels the running prompt and
the next send starts immediately with no leaked output.
Closes#8283, #8461.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/GrokProvider.test.ts Outdated
@github-actions

github-actionsBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.1 KiB13.3 KiB+172 B (+1.3%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−3 B (−0.0%)7.3 KiB
CodexLive turn WebSocket wire6.2 KiB6.4 KiB+175 B (+2.7%)7.8 KiB
CodexLive turn WebSocket decoded54.7 KiB55.6 KiB+910 B (+1.6%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.4 KiB13.5 KiB+24 B (+0.2%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+10 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.6 KiB6.6 KiB+14 B (+0.2%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.8 KiB0 B (0.0%)66.4 KiB
ClaudeLive turn messages10100 (0.0%)21

Baseline: 8efd4e9 · PR result: 2b9bde5 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Comment threadapps/server/src/provider/Layers/GrokProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
t3dotggand others added 2 commits September 1, 2026 18:23
…ns with Schema
Review follow-ups. A non-zero grok models exit printed help or error
text that could be read as model slugs or a login verdict. Only exit 0
is parsed now. The notification encoder uses Schema.fromJsonString to
satisfy the repo lint rule instead of raw JSON.stringify.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b7f5d8f. Configure here.

Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR makes cross-cutting production changes to Grok health checks, effective model defaults, prompt steering, and shared ACP cancellation/wire behavior. It also adds a static-analysis suppression, so the change requires human review under the configured criteria.

Notes:

  • No code objects were reviewed. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@t3dotgg
t3dotgg merged commit a434677 into mainSep 2, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the t3code/harden-grok-build-support branch September 2, 2026 01:48
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
Hermes model selection sent session/set_model unconditionally, including
when the session was already on the requested model. Grok's ACP fix
(pingdotgg#9154) made the mock agent reject set_model for ids it does not
advertise as switchable, which surfaced the redundancy: selecting the
session's current model failed instead of no-opping.
applyHermesAcpModelSelection now takes the session's current model id
(read from session setup at start, tracked on the session for turns) and
sends set_model only when the selection actually changes the model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QingonqJgq96d3byM5qRh9
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grok provider health check times out because it starts a full ACP session (and every MCP server)

2 participants

@t3dotgg@mavenskylab
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(grok): health check, model selection, and stop all work against the real CLI - #9154

Merged
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support
Sep 2, 2026
Merged

fix(grok): health check, model selection, and stop all work against the real CLI#9154
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Grok Build had a cluster of reliability problems that made it feel broken even when the CLI itself was fine:

  • The provider health check opened a full ACP session. authenticate could launch a browser login on its own, and session/new booted every configured MCP server, so background checks hung, timed out, and persisted error over a working install. It also never reported auth state.
  • Picking the built-in Grok Build model failed with unknown model id, because grok-build is the CLI's product name, not a model id its ACP accepts.
  • Stop did not stop. The next message queued behind the old prompt, which kept running to completion.
  • Mid-turn sends queued instead of interrupting like Claude and Codex.

What changed

Health check without a session.grok --version, then grok models for login state and slugs, then a single ACP initialize and reads models from _meta.modelState. No authenticate, no session/new. A failed initialize degrades to warning with the CLI's model list instead of error. XAI_API_KEY counts as authenticated. Against Grok CLI 1.0.13 this returns ready, authenticated, and both models with reasoning options in about 1.2 s.

grok-build means "the session's current model". It is never sent in session/set_model. No hardcoded alias to rot when the next model ships. The mock agent now advertises versioned ids like the real CLI so this cannot regress silently.

Stop actually cancels. This was the root cause behind both stop issues. effect-acp encoded notifications through the Request path, so session/cancel went out as {"id":"","headers":[]}. Grok CLI parses that as a malformed request and drops it. The mock agent was lenient and hid this. Notifications now serialize with no id. Verified live: Stop then a new send answers the new prompt immediately with nothing leaked from the old one. Before this fix the old prompt's output kept streaming into the new turn.

Mid-turn sends interrupt. Takes over #8286 by @mavenskylab with authorship preserved, plus one follow-up that replaces the eight-yieldNow sync loop with a Deferred the ACP runtime settles once the prompt RPC is registered.

Verification

  • Focused tests for the health check parser, model-state builder, product-slug handling, ACP notification encoding, and the existing Grok, Cursor, and ACP runtime suites. 211 passing.
  • Live against Grok CLI 1.0.13: health check snapshot, and stop-then-resend with wire capture of every frame T3 wrote to the agent.

Closes#7746, #5852, #7505, #6075, #8283, #8461.

Written by Claude Fable 5.1 in Claude Code.


Note

Medium Risk
Shared ACP protocol and cancel timing changes affect all ACP-backed providers, not only Grok; Grok steer adds epoch-based concurrency that must stay consistent with interrupt and settlement paths.

Overview
Fixes Grok reliability by aligning probes and turn control with the real CLI, and repairs ACP session/cancel so Grok (and other agents) actually receive cancellation frames.

Provider health check no longer runs authenticate or session/new. It probes grok --version, parses grok models for login state and slugs, then a short ACP initialize to read models from _meta.modelState. Unauthenticated CLIs error with a login hint; failed initialize degrades to warning with CLI-listed models. XAI_API_KEY overrides CLI login for auth reporting.

Model selection: the built-in grok-build slug is T3’s product name—it is never sent in session/set_model; choosing it keeps the session’s current ACP model (reasoning changes still apply to that model). The mock agent advertises versioned ids like production.

Mid-turn sends (steer) on Grok now session/cancel the in-flight prompt, then send the replacement under a prompt epoch / lifecycle semaphore, so new input interrupts like Claude/Codex instead of queueing behind the old prompt.

effect-acp: outbound notifications encode as proper JSON-RPC (no id or headers); RPC Interrupt control messages are dropped. AcpSessionRuntime.cancel awaits the cancel write before completing; prompt can signal dispatched once the prompt RPC is registered for steer races.

Reviewed by Cursor Bugbot for commit 2b9bde5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix Grok health check, model selection, and concurrent turn steering

  • Rewrites checkGrokProviderStatus to probe via ACP initialize only (no session creation), then fall back to grok models CLI output and built-in models; derives auth state from XAI_API_KEY or CLI login text
  • Treats the grok-build product slug as "keep current session model" in applyGrokAcpModelSelection — it is no longer sent through session/set_model; reasoning changes apply to the resolved current model
  • Reworks GrokAdapter.sendTurn with a prompt epoch and lifecycle semaphore so a concurrent turn cancels the active ACP prompt before starting a replacement, skips superseded prompts, preserves the original prompt when replacement prep fails, and emits exactly one terminal event per turn
  • Encodes outbound ACP notifications through encodeJsonRpcNotification without id or headers, and discards @effect/rpc/Interrupt messages so they are not sent to ACP agents
  • Risk: discoverGrokModelsViaAcpInitialize now sends only initialize — any code relying on session creation during discovery will no longer get it; sendNotification encoding failures now surface as ACP protocol parse errors rather than native TypeErrors

Macroscope summarized 2b9bde5.

mavenskylaband others added 6 commits September 1, 2026 18:10
Sending a follow-up on a Grok thread waited behind the in-flight ACP
prompt instead of interrupting like Claude/Codex. A steer now cancels
the current prompt and continues the same turn immediately.
Usage-limit exhaustion was already fixed on main by #8358.
Fixes#8283
Made by Grok 4.6 via the Grok harness.
Discarded and interrupted prompts settled turn state while holding
the prompt-lifecycle lock, so settlement could race interruptTurn
or the next sendTurn. Skip vs start still happens under that lock;
settlement now waits for the thread lock after the permit is released.
Made by Grok 4.6 via the Grok harness.
A failed empty steer advanced discardBeforeEpoch before the replacement
prompt prepared, so the live prompt skipped ACP and settled without
turn.completed. Discard the previous epoch only after prep succeeds.
Made by Grok 4.6 via the Grok harness.
The steer path forked session/prompt and then yielded eight times, hoping
the runtime had registered the RPC fiber before releasing the lifecycle
lock. The runtime now settles a Deferred once the prompt is the active
fiber, and the adapter waits on that or on prompt failure.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… as a model id
The Grok health check opened a full ACP session: initialize, authenticate,
session/new. authenticate can launch a browser login, and session/new
boots every configured MCP server. Background checks hung, timed out,
and persisted an error over a working install. The success branch also
hard-coded auth unknown.
The check now runs grok --version, then grok models for login state and
slugs, then a single ACP initialize and reads models from
_meta.modelState. A failed initialize degrades to warning with the CLI
list instead of error. XAI_API_KEY counts as authenticated.
grok-build is the CLI product name, not a model id its ACP accepts, so
session/set_model rejected it. It now means keep the session current
model and is never sent over the wire. The mock agent advertises
versioned ids like the real CLI so this cannot regress silently.
Closes#7746, #5852, #7505, #6075.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Notifications went out through the generic Request encoder, which added
id: "" and headers: []. Grok CLI parses that as a malformed request and
drops it, so Stop never reached the agent and the old prompt kept
running after the next send. The mock agent was lenient and hid this.
Notifications now serialize as {jsonrpc, method, params} with no id.
The client also stops emitting @effect/rpc/Interrupt frames, which ACP
agents log as Method not found.
Verified against Grok CLI 1.0.13: Stop cancels the running prompt and
the next send starts immediately with no leaked output.
Closes#8283, #8461.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/GrokProvider.test.ts Outdated
@github-actions

github-actionsBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.1 KiB13.3 KiB+172 B (+1.3%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−3 B (−0.0%)7.3 KiB
CodexLive turn WebSocket wire6.2 KiB6.4 KiB+175 B (+2.7%)7.8 KiB
CodexLive turn WebSocket decoded54.7 KiB55.6 KiB+910 B (+1.6%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.4 KiB13.5 KiB+24 B (+0.2%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+10 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.6 KiB6.6 KiB+14 B (+0.2%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.8 KiB0 B (0.0%)66.4 KiB
ClaudeLive turn messages10100 (0.0%)21

Baseline: 8efd4e9 · PR result: 2b9bde5 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Comment threadapps/server/src/provider/Layers/GrokProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
t3dotggand others added 2 commits September 1, 2026 18:23
…ns with Schema
Review follow-ups. A non-zero grok models exit printed help or error
text that could be read as model slugs or a login verdict. Only exit 0
is parsed now. The notification encoder uses Schema.fromJsonString to
satisfy the repo lint rule instead of raw JSON.stringify.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b7f5d8f. Configure here.

Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR makes cross-cutting production changes to Grok health checks, effective model defaults, prompt steering, and shared ACP cancellation/wire behavior. It also adds a static-analysis suppression, so the change requires human review under the configured criteria.

Notes:

  • No code objects were reviewed. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@t3dotgg
t3dotgg merged commit a434677 into mainSep 2, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the t3code/harden-grok-build-support branch September 2, 2026 01:48
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
Hermes model selection sent session/set_model unconditionally, including
when the session was already on the requested model. Grok's ACP fix
(pingdotgg#9154) made the mock agent reject set_model for ids it does not
advertise as switchable, which surfaced the redundancy: selecting the
session's current model failed instead of no-opping.
applyHermesAcpModelSelection now takes the session's current model id
(read from session setup at start, tracked on the session for turns) and
sends set_model only when the selection actually changes the model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QingonqJgq96d3byM5qRh9
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grok provider health check times out because it starts a full ACP session (and every MCP server)

2 participants

@t3dotgg@mavenskylab
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(grok): health check, model selection, and stop all work against the real CLI - #9154

Merged
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support
Sep 2, 2026
Merged

fix(grok): health check, model selection, and stop all work against the real CLI#9154
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Grok Build had a cluster of reliability problems that made it feel broken even when the CLI itself was fine:

  • The provider health check opened a full ACP session. authenticate could launch a browser login on its own, and session/new booted every configured MCP server, so background checks hung, timed out, and persisted error over a working install. It also never reported auth state.
  • Picking the built-in Grok Build model failed with unknown model id, because grok-build is the CLI's product name, not a model id its ACP accepts.
  • Stop did not stop. The next message queued behind the old prompt, which kept running to completion.
  • Mid-turn sends queued instead of interrupting like Claude and Codex.

What changed

Health check without a session.grok --version, then grok models for login state and slugs, then a single ACP initialize and reads models from _meta.modelState. No authenticate, no session/new. A failed initialize degrades to warning with the CLI's model list instead of error. XAI_API_KEY counts as authenticated. Against Grok CLI 1.0.13 this returns ready, authenticated, and both models with reasoning options in about 1.2 s.

grok-build means "the session's current model". It is never sent in session/set_model. No hardcoded alias to rot when the next model ships. The mock agent now advertises versioned ids like the real CLI so this cannot regress silently.

Stop actually cancels. This was the root cause behind both stop issues. effect-acp encoded notifications through the Request path, so session/cancel went out as {"id":"","headers":[]}. Grok CLI parses that as a malformed request and drops it. The mock agent was lenient and hid this. Notifications now serialize with no id. Verified live: Stop then a new send answers the new prompt immediately with nothing leaked from the old one. Before this fix the old prompt's output kept streaming into the new turn.

Mid-turn sends interrupt. Takes over #8286 by @mavenskylab with authorship preserved, plus one follow-up that replaces the eight-yieldNow sync loop with a Deferred the ACP runtime settles once the prompt RPC is registered.

Verification

  • Focused tests for the health check parser, model-state builder, product-slug handling, ACP notification encoding, and the existing Grok, Cursor, and ACP runtime suites. 211 passing.
  • Live against Grok CLI 1.0.13: health check snapshot, and stop-then-resend with wire capture of every frame T3 wrote to the agent.

Closes#7746, #5852, #7505, #6075, #8283, #8461.

Written by Claude Fable 5.1 in Claude Code.


Note

Medium Risk
Shared ACP protocol and cancel timing changes affect all ACP-backed providers, not only Grok; Grok steer adds epoch-based concurrency that must stay consistent with interrupt and settlement paths.

Overview
Fixes Grok reliability by aligning probes and turn control with the real CLI, and repairs ACP session/cancel so Grok (and other agents) actually receive cancellation frames.

Provider health check no longer runs authenticate or session/new. It probes grok --version, parses grok models for login state and slugs, then a short ACP initialize to read models from _meta.modelState. Unauthenticated CLIs error with a login hint; failed initialize degrades to warning with CLI-listed models. XAI_API_KEY overrides CLI login for auth reporting.

Model selection: the built-in grok-build slug is T3’s product name—it is never sent in session/set_model; choosing it keeps the session’s current ACP model (reasoning changes still apply to that model). The mock agent advertises versioned ids like production.

Mid-turn sends (steer) on Grok now session/cancel the in-flight prompt, then send the replacement under a prompt epoch / lifecycle semaphore, so new input interrupts like Claude/Codex instead of queueing behind the old prompt.

effect-acp: outbound notifications encode as proper JSON-RPC (no id or headers); RPC Interrupt control messages are dropped. AcpSessionRuntime.cancel awaits the cancel write before completing; prompt can signal dispatched once the prompt RPC is registered for steer races.

Reviewed by Cursor Bugbot for commit 2b9bde5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix Grok health check, model selection, and concurrent turn steering

  • Rewrites checkGrokProviderStatus to probe via ACP initialize only (no session creation), then fall back to grok models CLI output and built-in models; derives auth state from XAI_API_KEY or CLI login text
  • Treats the grok-build product slug as "keep current session model" in applyGrokAcpModelSelection — it is no longer sent through session/set_model; reasoning changes apply to the resolved current model
  • Reworks GrokAdapter.sendTurn with a prompt epoch and lifecycle semaphore so a concurrent turn cancels the active ACP prompt before starting a replacement, skips superseded prompts, preserves the original prompt when replacement prep fails, and emits exactly one terminal event per turn
  • Encodes outbound ACP notifications through encodeJsonRpcNotification without id or headers, and discards @effect/rpc/Interrupt messages so they are not sent to ACP agents
  • Risk: discoverGrokModelsViaAcpInitialize now sends only initialize — any code relying on session creation during discovery will no longer get it; sendNotification encoding failures now surface as ACP protocol parse errors rather than native TypeErrors

Macroscope summarized 2b9bde5.

mavenskylaband others added 6 commits September 1, 2026 18:10
Sending a follow-up on a Grok thread waited behind the in-flight ACP
prompt instead of interrupting like Claude/Codex. A steer now cancels
the current prompt and continues the same turn immediately.
Usage-limit exhaustion was already fixed on main by #8358.
Fixes#8283
Made by Grok 4.6 via the Grok harness.
Discarded and interrupted prompts settled turn state while holding
the prompt-lifecycle lock, so settlement could race interruptTurn
or the next sendTurn. Skip vs start still happens under that lock;
settlement now waits for the thread lock after the permit is released.
Made by Grok 4.6 via the Grok harness.
A failed empty steer advanced discardBeforeEpoch before the replacement
prompt prepared, so the live prompt skipped ACP and settled without
turn.completed. Discard the previous epoch only after prep succeeds.
Made by Grok 4.6 via the Grok harness.
The steer path forked session/prompt and then yielded eight times, hoping
the runtime had registered the RPC fiber before releasing the lifecycle
lock. The runtime now settles a Deferred once the prompt is the active
fiber, and the adapter waits on that or on prompt failure.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… as a model id
The Grok health check opened a full ACP session: initialize, authenticate,
session/new. authenticate can launch a browser login, and session/new
boots every configured MCP server. Background checks hung, timed out,
and persisted an error over a working install. The success branch also
hard-coded auth unknown.
The check now runs grok --version, then grok models for login state and
slugs, then a single ACP initialize and reads models from
_meta.modelState. A failed initialize degrades to warning with the CLI
list instead of error. XAI_API_KEY counts as authenticated.
grok-build is the CLI product name, not a model id its ACP accepts, so
session/set_model rejected it. It now means keep the session current
model and is never sent over the wire. The mock agent advertises
versioned ids like the real CLI so this cannot regress silently.
Closes#7746, #5852, #7505, #6075.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Notifications went out through the generic Request encoder, which added
id: "" and headers: []. Grok CLI parses that as a malformed request and
drops it, so Stop never reached the agent and the old prompt kept
running after the next send. The mock agent was lenient and hid this.
Notifications now serialize as {jsonrpc, method, params} with no id.
The client also stops emitting @effect/rpc/Interrupt frames, which ACP
agents log as Method not found.
Verified against Grok CLI 1.0.13: Stop cancels the running prompt and
the next send starts immediately with no leaked output.
Closes#8283, #8461.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/GrokProvider.test.ts Outdated
@github-actions

github-actionsBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.1 KiB13.3 KiB+172 B (+1.3%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−3 B (−0.0%)7.3 KiB
CodexLive turn WebSocket wire6.2 KiB6.4 KiB+175 B (+2.7%)7.8 KiB
CodexLive turn WebSocket decoded54.7 KiB55.6 KiB+910 B (+1.6%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.4 KiB13.5 KiB+24 B (+0.2%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+10 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.6 KiB6.6 KiB+14 B (+0.2%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.8 KiB0 B (0.0%)66.4 KiB
ClaudeLive turn messages10100 (0.0%)21

Baseline: 8efd4e9 · PR result: 2b9bde5 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Comment threadapps/server/src/provider/Layers/GrokProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
t3dotggand others added 2 commits September 1, 2026 18:23
…ns with Schema
Review follow-ups. A non-zero grok models exit printed help or error
text that could be read as model slugs or a login verdict. Only exit 0
is parsed now. The notification encoder uses Schema.fromJsonString to
satisfy the repo lint rule instead of raw JSON.stringify.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b7f5d8f. Configure here.

Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR makes cross-cutting production changes to Grok health checks, effective model defaults, prompt steering, and shared ACP cancellation/wire behavior. It also adds a static-analysis suppression, so the change requires human review under the configured criteria.

Notes:

  • No code objects were reviewed. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@t3dotgg
t3dotgg merged commit a434677 into mainSep 2, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the t3code/harden-grok-build-support branch September 2, 2026 01:48
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
Hermes model selection sent session/set_model unconditionally, including
when the session was already on the requested model. Grok's ACP fix
(pingdotgg#9154) made the mock agent reject set_model for ids it does not
advertise as switchable, which surfaced the redundancy: selecting the
session's current model failed instead of no-opping.
applyHermesAcpModelSelection now takes the session's current model id
(read from session setup at start, tracked on the session for turns) and
sends set_model only when the selection actually changes the model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QingonqJgq96d3byM5qRh9
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grok provider health check times out because it starts a full ACP session (and every MCP server)

2 participants

@t3dotgg@mavenskylab
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(grok): health check, model selection, and stop all work against the real CLI - #9154

Merged
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support
Sep 2, 2026
Merged

fix(grok): health check, model selection, and stop all work against the real CLI#9154
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Grok Build had a cluster of reliability problems that made it feel broken even when the CLI itself was fine:

  • The provider health check opened a full ACP session. authenticate could launch a browser login on its own, and session/new booted every configured MCP server, so background checks hung, timed out, and persisted error over a working install. It also never reported auth state.
  • Picking the built-in Grok Build model failed with unknown model id, because grok-build is the CLI's product name, not a model id its ACP accepts.
  • Stop did not stop. The next message queued behind the old prompt, which kept running to completion.
  • Mid-turn sends queued instead of interrupting like Claude and Codex.

What changed

Health check without a session.grok --version, then grok models for login state and slugs, then a single ACP initialize and reads models from _meta.modelState. No authenticate, no session/new. A failed initialize degrades to warning with the CLI's model list instead of error. XAI_API_KEY counts as authenticated. Against Grok CLI 1.0.13 this returns ready, authenticated, and both models with reasoning options in about 1.2 s.

grok-build means "the session's current model". It is never sent in session/set_model. No hardcoded alias to rot when the next model ships. The mock agent now advertises versioned ids like the real CLI so this cannot regress silently.

Stop actually cancels. This was the root cause behind both stop issues. effect-acp encoded notifications through the Request path, so session/cancel went out as {"id":"","headers":[]}. Grok CLI parses that as a malformed request and drops it. The mock agent was lenient and hid this. Notifications now serialize with no id. Verified live: Stop then a new send answers the new prompt immediately with nothing leaked from the old one. Before this fix the old prompt's output kept streaming into the new turn.

Mid-turn sends interrupt. Takes over #8286 by @mavenskylab with authorship preserved, plus one follow-up that replaces the eight-yieldNow sync loop with a Deferred the ACP runtime settles once the prompt RPC is registered.

Verification

  • Focused tests for the health check parser, model-state builder, product-slug handling, ACP notification encoding, and the existing Grok, Cursor, and ACP runtime suites. 211 passing.
  • Live against Grok CLI 1.0.13: health check snapshot, and stop-then-resend with wire capture of every frame T3 wrote to the agent.

Closes#7746, #5852, #7505, #6075, #8283, #8461.

Written by Claude Fable 5.1 in Claude Code.


Note

Medium Risk
Shared ACP protocol and cancel timing changes affect all ACP-backed providers, not only Grok; Grok steer adds epoch-based concurrency that must stay consistent with interrupt and settlement paths.

Overview
Fixes Grok reliability by aligning probes and turn control with the real CLI, and repairs ACP session/cancel so Grok (and other agents) actually receive cancellation frames.

Provider health check no longer runs authenticate or session/new. It probes grok --version, parses grok models for login state and slugs, then a short ACP initialize to read models from _meta.modelState. Unauthenticated CLIs error with a login hint; failed initialize degrades to warning with CLI-listed models. XAI_API_KEY overrides CLI login for auth reporting.

Model selection: the built-in grok-build slug is T3’s product name—it is never sent in session/set_model; choosing it keeps the session’s current ACP model (reasoning changes still apply to that model). The mock agent advertises versioned ids like production.

Mid-turn sends (steer) on Grok now session/cancel the in-flight prompt, then send the replacement under a prompt epoch / lifecycle semaphore, so new input interrupts like Claude/Codex instead of queueing behind the old prompt.

effect-acp: outbound notifications encode as proper JSON-RPC (no id or headers); RPC Interrupt control messages are dropped. AcpSessionRuntime.cancel awaits the cancel write before completing; prompt can signal dispatched once the prompt RPC is registered for steer races.

Reviewed by Cursor Bugbot for commit 2b9bde5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix Grok health check, model selection, and concurrent turn steering

  • Rewrites checkGrokProviderStatus to probe via ACP initialize only (no session creation), then fall back to grok models CLI output and built-in models; derives auth state from XAI_API_KEY or CLI login text
  • Treats the grok-build product slug as "keep current session model" in applyGrokAcpModelSelection — it is no longer sent through session/set_model; reasoning changes apply to the resolved current model
  • Reworks GrokAdapter.sendTurn with a prompt epoch and lifecycle semaphore so a concurrent turn cancels the active ACP prompt before starting a replacement, skips superseded prompts, preserves the original prompt when replacement prep fails, and emits exactly one terminal event per turn
  • Encodes outbound ACP notifications through encodeJsonRpcNotification without id or headers, and discards @effect/rpc/Interrupt messages so they are not sent to ACP agents
  • Risk: discoverGrokModelsViaAcpInitialize now sends only initialize — any code relying on session creation during discovery will no longer get it; sendNotification encoding failures now surface as ACP protocol parse errors rather than native TypeErrors

Macroscope summarized 2b9bde5.

mavenskylaband others added 6 commits September 1, 2026 18:10
Sending a follow-up on a Grok thread waited behind the in-flight ACP
prompt instead of interrupting like Claude/Codex. A steer now cancels
the current prompt and continues the same turn immediately.
Usage-limit exhaustion was already fixed on main by #8358.
Fixes#8283
Made by Grok 4.6 via the Grok harness.
Discarded and interrupted prompts settled turn state while holding
the prompt-lifecycle lock, so settlement could race interruptTurn
or the next sendTurn. Skip vs start still happens under that lock;
settlement now waits for the thread lock after the permit is released.
Made by Grok 4.6 via the Grok harness.
A failed empty steer advanced discardBeforeEpoch before the replacement
prompt prepared, so the live prompt skipped ACP and settled without
turn.completed. Discard the previous epoch only after prep succeeds.
Made by Grok 4.6 via the Grok harness.
The steer path forked session/prompt and then yielded eight times, hoping
the runtime had registered the RPC fiber before releasing the lifecycle
lock. The runtime now settles a Deferred once the prompt is the active
fiber, and the adapter waits on that or on prompt failure.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… as a model id
The Grok health check opened a full ACP session: initialize, authenticate,
session/new. authenticate can launch a browser login, and session/new
boots every configured MCP server. Background checks hung, timed out,
and persisted an error over a working install. The success branch also
hard-coded auth unknown.
The check now runs grok --version, then grok models for login state and
slugs, then a single ACP initialize and reads models from
_meta.modelState. A failed initialize degrades to warning with the CLI
list instead of error. XAI_API_KEY counts as authenticated.
grok-build is the CLI product name, not a model id its ACP accepts, so
session/set_model rejected it. It now means keep the session current
model and is never sent over the wire. The mock agent advertises
versioned ids like the real CLI so this cannot regress silently.
Closes#7746, #5852, #7505, #6075.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Notifications went out through the generic Request encoder, which added
id: "" and headers: []. Grok CLI parses that as a malformed request and
drops it, so Stop never reached the agent and the old prompt kept
running after the next send. The mock agent was lenient and hid this.
Notifications now serialize as {jsonrpc, method, params} with no id.
The client also stops emitting @effect/rpc/Interrupt frames, which ACP
agents log as Method not found.
Verified against Grok CLI 1.0.13: Stop cancels the running prompt and
the next send starts immediately with no leaked output.
Closes#8283, #8461.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/GrokProvider.test.ts Outdated
@github-actions

github-actionsBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.1 KiB13.3 KiB+172 B (+1.3%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−3 B (−0.0%)7.3 KiB
CodexLive turn WebSocket wire6.2 KiB6.4 KiB+175 B (+2.7%)7.8 KiB
CodexLive turn WebSocket decoded54.7 KiB55.6 KiB+910 B (+1.6%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.4 KiB13.5 KiB+24 B (+0.2%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+10 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.6 KiB6.6 KiB+14 B (+0.2%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.8 KiB0 B (0.0%)66.4 KiB
ClaudeLive turn messages10100 (0.0%)21

Baseline: 8efd4e9 · PR result: 2b9bde5 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Comment threadapps/server/src/provider/Layers/GrokProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
t3dotggand others added 2 commits September 1, 2026 18:23
…ns with Schema
Review follow-ups. A non-zero grok models exit printed help or error
text that could be read as model slugs or a login verdict. Only exit 0
is parsed now. The notification encoder uses Schema.fromJsonString to
satisfy the repo lint rule instead of raw JSON.stringify.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b7f5d8f. Configure here.

Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR makes cross-cutting production changes to Grok health checks, effective model defaults, prompt steering, and shared ACP cancellation/wire behavior. It also adds a static-analysis suppression, so the change requires human review under the configured criteria.

Notes:

  • No code objects were reviewed. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@t3dotgg
t3dotgg merged commit a434677 into mainSep 2, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the t3code/harden-grok-build-support branch September 2, 2026 01:48
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
Hermes model selection sent session/set_model unconditionally, including
when the session was already on the requested model. Grok's ACP fix
(pingdotgg#9154) made the mock agent reject set_model for ids it does not
advertise as switchable, which surfaced the redundancy: selecting the
session's current model failed instead of no-opping.
applyHermesAcpModelSelection now takes the session's current model id
(read from session setup at start, tracked on the session for turns) and
sends set_model only when the selection actually changes the model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QingonqJgq96d3byM5qRh9
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grok provider health check times out because it starts a full ACP session (and every MCP server)

2 participants

@t3dotgg@mavenskylab
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(grok): health check, model selection, and stop all work against the real CLI - #9154

Merged
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support
Sep 2, 2026
Merged

fix(grok): health check, model selection, and stop all work against the real CLI#9154
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Grok Build had a cluster of reliability problems that made it feel broken even when the CLI itself was fine:

  • The provider health check opened a full ACP session. authenticate could launch a browser login on its own, and session/new booted every configured MCP server, so background checks hung, timed out, and persisted error over a working install. It also never reported auth state.
  • Picking the built-in Grok Build model failed with unknown model id, because grok-build is the CLI's product name, not a model id its ACP accepts.
  • Stop did not stop. The next message queued behind the old prompt, which kept running to completion.
  • Mid-turn sends queued instead of interrupting like Claude and Codex.

What changed

Health check without a session.grok --version, then grok models for login state and slugs, then a single ACP initialize and reads models from _meta.modelState. No authenticate, no session/new. A failed initialize degrades to warning with the CLI's model list instead of error. XAI_API_KEY counts as authenticated. Against Grok CLI 1.0.13 this returns ready, authenticated, and both models with reasoning options in about 1.2 s.

grok-build means "the session's current model". It is never sent in session/set_model. No hardcoded alias to rot when the next model ships. The mock agent now advertises versioned ids like the real CLI so this cannot regress silently.

Stop actually cancels. This was the root cause behind both stop issues. effect-acp encoded notifications through the Request path, so session/cancel went out as {"id":"","headers":[]}. Grok CLI parses that as a malformed request and drops it. The mock agent was lenient and hid this. Notifications now serialize with no id. Verified live: Stop then a new send answers the new prompt immediately with nothing leaked from the old one. Before this fix the old prompt's output kept streaming into the new turn.

Mid-turn sends interrupt. Takes over #8286 by @mavenskylab with authorship preserved, plus one follow-up that replaces the eight-yieldNow sync loop with a Deferred the ACP runtime settles once the prompt RPC is registered.

Verification

  • Focused tests for the health check parser, model-state builder, product-slug handling, ACP notification encoding, and the existing Grok, Cursor, and ACP runtime suites. 211 passing.
  • Live against Grok CLI 1.0.13: health check snapshot, and stop-then-resend with wire capture of every frame T3 wrote to the agent.

Closes#7746, #5852, #7505, #6075, #8283, #8461.

Written by Claude Fable 5.1 in Claude Code.


Note

Medium Risk
Shared ACP protocol and cancel timing changes affect all ACP-backed providers, not only Grok; Grok steer adds epoch-based concurrency that must stay consistent with interrupt and settlement paths.

Overview
Fixes Grok reliability by aligning probes and turn control with the real CLI, and repairs ACP session/cancel so Grok (and other agents) actually receive cancellation frames.

Provider health check no longer runs authenticate or session/new. It probes grok --version, parses grok models for login state and slugs, then a short ACP initialize to read models from _meta.modelState. Unauthenticated CLIs error with a login hint; failed initialize degrades to warning with CLI-listed models. XAI_API_KEY overrides CLI login for auth reporting.

Model selection: the built-in grok-build slug is T3’s product name—it is never sent in session/set_model; choosing it keeps the session’s current ACP model (reasoning changes still apply to that model). The mock agent advertises versioned ids like production.

Mid-turn sends (steer) on Grok now session/cancel the in-flight prompt, then send the replacement under a prompt epoch / lifecycle semaphore, so new input interrupts like Claude/Codex instead of queueing behind the old prompt.

effect-acp: outbound notifications encode as proper JSON-RPC (no id or headers); RPC Interrupt control messages are dropped. AcpSessionRuntime.cancel awaits the cancel write before completing; prompt can signal dispatched once the prompt RPC is registered for steer races.

Reviewed by Cursor Bugbot for commit 2b9bde5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix Grok health check, model selection, and concurrent turn steering

  • Rewrites checkGrokProviderStatus to probe via ACP initialize only (no session creation), then fall back to grok models CLI output and built-in models; derives auth state from XAI_API_KEY or CLI login text
  • Treats the grok-build product slug as "keep current session model" in applyGrokAcpModelSelection — it is no longer sent through session/set_model; reasoning changes apply to the resolved current model
  • Reworks GrokAdapter.sendTurn with a prompt epoch and lifecycle semaphore so a concurrent turn cancels the active ACP prompt before starting a replacement, skips superseded prompts, preserves the original prompt when replacement prep fails, and emits exactly one terminal event per turn
  • Encodes outbound ACP notifications through encodeJsonRpcNotification without id or headers, and discards @effect/rpc/Interrupt messages so they are not sent to ACP agents
  • Risk: discoverGrokModelsViaAcpInitialize now sends only initialize — any code relying on session creation during discovery will no longer get it; sendNotification encoding failures now surface as ACP protocol parse errors rather than native TypeErrors

Macroscope summarized 2b9bde5.

mavenskylaband others added 6 commits September 1, 2026 18:10
Sending a follow-up on a Grok thread waited behind the in-flight ACP
prompt instead of interrupting like Claude/Codex. A steer now cancels
the current prompt and continues the same turn immediately.
Usage-limit exhaustion was already fixed on main by #8358.
Fixes#8283
Made by Grok 4.6 via the Grok harness.
Discarded and interrupted prompts settled turn state while holding
the prompt-lifecycle lock, so settlement could race interruptTurn
or the next sendTurn. Skip vs start still happens under that lock;
settlement now waits for the thread lock after the permit is released.
Made by Grok 4.6 via the Grok harness.
A failed empty steer advanced discardBeforeEpoch before the replacement
prompt prepared, so the live prompt skipped ACP and settled without
turn.completed. Discard the previous epoch only after prep succeeds.
Made by Grok 4.6 via the Grok harness.
The steer path forked session/prompt and then yielded eight times, hoping
the runtime had registered the RPC fiber before releasing the lifecycle
lock. The runtime now settles a Deferred once the prompt is the active
fiber, and the adapter waits on that or on prompt failure.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… as a model id
The Grok health check opened a full ACP session: initialize, authenticate,
session/new. authenticate can launch a browser login, and session/new
boots every configured MCP server. Background checks hung, timed out,
and persisted an error over a working install. The success branch also
hard-coded auth unknown.
The check now runs grok --version, then grok models for login state and
slugs, then a single ACP initialize and reads models from
_meta.modelState. A failed initialize degrades to warning with the CLI
list instead of error. XAI_API_KEY counts as authenticated.
grok-build is the CLI product name, not a model id its ACP accepts, so
session/set_model rejected it. It now means keep the session current
model and is never sent over the wire. The mock agent advertises
versioned ids like the real CLI so this cannot regress silently.
Closes#7746, #5852, #7505, #6075.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Notifications went out through the generic Request encoder, which added
id: "" and headers: []. Grok CLI parses that as a malformed request and
drops it, so Stop never reached the agent and the old prompt kept
running after the next send. The mock agent was lenient and hid this.
Notifications now serialize as {jsonrpc, method, params} with no id.
The client also stops emitting @effect/rpc/Interrupt frames, which ACP
agents log as Method not found.
Verified against Grok CLI 1.0.13: Stop cancels the running prompt and
the next send starts immediately with no leaked output.
Closes#8283, #8461.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/GrokProvider.test.ts Outdated
@github-actions

github-actionsBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.1 KiB13.3 KiB+172 B (+1.3%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−3 B (−0.0%)7.3 KiB
CodexLive turn WebSocket wire6.2 KiB6.4 KiB+175 B (+2.7%)7.8 KiB
CodexLive turn WebSocket decoded54.7 KiB55.6 KiB+910 B (+1.6%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.4 KiB13.5 KiB+24 B (+0.2%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+10 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.6 KiB6.6 KiB+14 B (+0.2%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.8 KiB0 B (0.0%)66.4 KiB
ClaudeLive turn messages10100 (0.0%)21

Baseline: 8efd4e9 · PR result: 2b9bde5 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Comment threadapps/server/src/provider/Layers/GrokProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
t3dotggand others added 2 commits September 1, 2026 18:23
…ns with Schema
Review follow-ups. A non-zero grok models exit printed help or error
text that could be read as model slugs or a login verdict. Only exit 0
is parsed now. The notification encoder uses Schema.fromJsonString to
satisfy the repo lint rule instead of raw JSON.stringify.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b7f5d8f. Configure here.

Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR makes cross-cutting production changes to Grok health checks, effective model defaults, prompt steering, and shared ACP cancellation/wire behavior. It also adds a static-analysis suppression, so the change requires human review under the configured criteria.

Notes:

  • No code objects were reviewed. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@t3dotgg
t3dotgg merged commit a434677 into mainSep 2, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the t3code/harden-grok-build-support branch September 2, 2026 01:48
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
Hermes model selection sent session/set_model unconditionally, including
when the session was already on the requested model. Grok's ACP fix
(pingdotgg#9154) made the mock agent reject set_model for ids it does not
advertise as switchable, which surfaced the redundancy: selecting the
session's current model failed instead of no-opping.
applyHermesAcpModelSelection now takes the session's current model id
(read from session setup at start, tracked on the session for turns) and
sends set_model only when the selection actually changes the model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QingonqJgq96d3byM5qRh9
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grok provider health check times out because it starts a full ACP session (and every MCP server)

2 participants

@t3dotgg@mavenskylab
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(grok): health check, model selection, and stop all work against the real CLI - #9154

Merged
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support
Sep 2, 2026
Merged

fix(grok): health check, model selection, and stop all work against the real CLI#9154
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Grok Build had a cluster of reliability problems that made it feel broken even when the CLI itself was fine:

  • The provider health check opened a full ACP session. authenticate could launch a browser login on its own, and session/new booted every configured MCP server, so background checks hung, timed out, and persisted error over a working install. It also never reported auth state.
  • Picking the built-in Grok Build model failed with unknown model id, because grok-build is the CLI's product name, not a model id its ACP accepts.
  • Stop did not stop. The next message queued behind the old prompt, which kept running to completion.
  • Mid-turn sends queued instead of interrupting like Claude and Codex.

What changed

Health check without a session.grok --version, then grok models for login state and slugs, then a single ACP initialize and reads models from _meta.modelState. No authenticate, no session/new. A failed initialize degrades to warning with the CLI's model list instead of error. XAI_API_KEY counts as authenticated. Against Grok CLI 1.0.13 this returns ready, authenticated, and both models with reasoning options in about 1.2 s.

grok-build means "the session's current model". It is never sent in session/set_model. No hardcoded alias to rot when the next model ships. The mock agent now advertises versioned ids like the real CLI so this cannot regress silently.

Stop actually cancels. This was the root cause behind both stop issues. effect-acp encoded notifications through the Request path, so session/cancel went out as {"id":"","headers":[]}. Grok CLI parses that as a malformed request and drops it. The mock agent was lenient and hid this. Notifications now serialize with no id. Verified live: Stop then a new send answers the new prompt immediately with nothing leaked from the old one. Before this fix the old prompt's output kept streaming into the new turn.

Mid-turn sends interrupt. Takes over #8286 by @mavenskylab with authorship preserved, plus one follow-up that replaces the eight-yieldNow sync loop with a Deferred the ACP runtime settles once the prompt RPC is registered.

Verification

  • Focused tests for the health check parser, model-state builder, product-slug handling, ACP notification encoding, and the existing Grok, Cursor, and ACP runtime suites. 211 passing.
  • Live against Grok CLI 1.0.13: health check snapshot, and stop-then-resend with wire capture of every frame T3 wrote to the agent.

Closes#7746, #5852, #7505, #6075, #8283, #8461.

Written by Claude Fable 5.1 in Claude Code.


Note

Medium Risk
Shared ACP protocol and cancel timing changes affect all ACP-backed providers, not only Grok; Grok steer adds epoch-based concurrency that must stay consistent with interrupt and settlement paths.

Overview
Fixes Grok reliability by aligning probes and turn control with the real CLI, and repairs ACP session/cancel so Grok (and other agents) actually receive cancellation frames.

Provider health check no longer runs authenticate or session/new. It probes grok --version, parses grok models for login state and slugs, then a short ACP initialize to read models from _meta.modelState. Unauthenticated CLIs error with a login hint; failed initialize degrades to warning with CLI-listed models. XAI_API_KEY overrides CLI login for auth reporting.

Model selection: the built-in grok-build slug is T3’s product name—it is never sent in session/set_model; choosing it keeps the session’s current ACP model (reasoning changes still apply to that model). The mock agent advertises versioned ids like production.

Mid-turn sends (steer) on Grok now session/cancel the in-flight prompt, then send the replacement under a prompt epoch / lifecycle semaphore, so new input interrupts like Claude/Codex instead of queueing behind the old prompt.

effect-acp: outbound notifications encode as proper JSON-RPC (no id or headers); RPC Interrupt control messages are dropped. AcpSessionRuntime.cancel awaits the cancel write before completing; prompt can signal dispatched once the prompt RPC is registered for steer races.

Reviewed by Cursor Bugbot for commit 2b9bde5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix Grok health check, model selection, and concurrent turn steering

  • Rewrites checkGrokProviderStatus to probe via ACP initialize only (no session creation), then fall back to grok models CLI output and built-in models; derives auth state from XAI_API_KEY or CLI login text
  • Treats the grok-build product slug as "keep current session model" in applyGrokAcpModelSelection — it is no longer sent through session/set_model; reasoning changes apply to the resolved current model
  • Reworks GrokAdapter.sendTurn with a prompt epoch and lifecycle semaphore so a concurrent turn cancels the active ACP prompt before starting a replacement, skips superseded prompts, preserves the original prompt when replacement prep fails, and emits exactly one terminal event per turn
  • Encodes outbound ACP notifications through encodeJsonRpcNotification without id or headers, and discards @effect/rpc/Interrupt messages so they are not sent to ACP agents
  • Risk: discoverGrokModelsViaAcpInitialize now sends only initialize — any code relying on session creation during discovery will no longer get it; sendNotification encoding failures now surface as ACP protocol parse errors rather than native TypeErrors

Macroscope summarized 2b9bde5.

mavenskylaband others added 6 commits September 1, 2026 18:10
Sending a follow-up on a Grok thread waited behind the in-flight ACP
prompt instead of interrupting like Claude/Codex. A steer now cancels
the current prompt and continues the same turn immediately.
Usage-limit exhaustion was already fixed on main by #8358.
Fixes#8283
Made by Grok 4.6 via the Grok harness.
Discarded and interrupted prompts settled turn state while holding
the prompt-lifecycle lock, so settlement could race interruptTurn
or the next sendTurn. Skip vs start still happens under that lock;
settlement now waits for the thread lock after the permit is released.
Made by Grok 4.6 via the Grok harness.
A failed empty steer advanced discardBeforeEpoch before the replacement
prompt prepared, so the live prompt skipped ACP and settled without
turn.completed. Discard the previous epoch only after prep succeeds.
Made by Grok 4.6 via the Grok harness.
The steer path forked session/prompt and then yielded eight times, hoping
the runtime had registered the RPC fiber before releasing the lifecycle
lock. The runtime now settles a Deferred once the prompt is the active
fiber, and the adapter waits on that or on prompt failure.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… as a model id
The Grok health check opened a full ACP session: initialize, authenticate,
session/new. authenticate can launch a browser login, and session/new
boots every configured MCP server. Background checks hung, timed out,
and persisted an error over a working install. The success branch also
hard-coded auth unknown.
The check now runs grok --version, then grok models for login state and
slugs, then a single ACP initialize and reads models from
_meta.modelState. A failed initialize degrades to warning with the CLI
list instead of error. XAI_API_KEY counts as authenticated.
grok-build is the CLI product name, not a model id its ACP accepts, so
session/set_model rejected it. It now means keep the session current
model and is never sent over the wire. The mock agent advertises
versioned ids like the real CLI so this cannot regress silently.
Closes#7746, #5852, #7505, #6075.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Notifications went out through the generic Request encoder, which added
id: "" and headers: []. Grok CLI parses that as a malformed request and
drops it, so Stop never reached the agent and the old prompt kept
running after the next send. The mock agent was lenient and hid this.
Notifications now serialize as {jsonrpc, method, params} with no id.
The client also stops emitting @effect/rpc/Interrupt frames, which ACP
agents log as Method not found.
Verified against Grok CLI 1.0.13: Stop cancels the running prompt and
the next send starts immediately with no leaked output.
Closes#8283, #8461.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/GrokProvider.test.ts Outdated
@github-actions

github-actionsBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.1 KiB13.3 KiB+172 B (+1.3%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−3 B (−0.0%)7.3 KiB
CodexLive turn WebSocket wire6.2 KiB6.4 KiB+175 B (+2.7%)7.8 KiB
CodexLive turn WebSocket decoded54.7 KiB55.6 KiB+910 B (+1.6%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.4 KiB13.5 KiB+24 B (+0.2%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+10 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.6 KiB6.6 KiB+14 B (+0.2%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.8 KiB0 B (0.0%)66.4 KiB
ClaudeLive turn messages10100 (0.0%)21

Baseline: 8efd4e9 · PR result: 2b9bde5 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Comment threadapps/server/src/provider/Layers/GrokProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
t3dotggand others added 2 commits September 1, 2026 18:23
…ns with Schema
Review follow-ups. A non-zero grok models exit printed help or error
text that could be read as model slugs or a login verdict. Only exit 0
is parsed now. The notification encoder uses Schema.fromJsonString to
satisfy the repo lint rule instead of raw JSON.stringify.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b7f5d8f. Configure here.

Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR makes cross-cutting production changes to Grok health checks, effective model defaults, prompt steering, and shared ACP cancellation/wire behavior. It also adds a static-analysis suppression, so the change requires human review under the configured criteria.

Notes:

  • No code objects were reviewed. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@t3dotgg
t3dotgg merged commit a434677 into mainSep 2, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the t3code/harden-grok-build-support branch September 2, 2026 01:48
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
Hermes model selection sent session/set_model unconditionally, including
when the session was already on the requested model. Grok's ACP fix
(pingdotgg#9154) made the mock agent reject set_model for ids it does not
advertise as switchable, which surfaced the redundancy: selecting the
session's current model failed instead of no-opping.
applyHermesAcpModelSelection now takes the session's current model id
(read from session setup at start, tracked on the session for turns) and
sends set_model only when the selection actually changes the model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QingonqJgq96d3byM5qRh9
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grok provider health check times out because it starts a full ACP session (and every MCP server)

2 participants

@t3dotgg@mavenskylab
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(grok): health check, model selection, and stop all work against the real CLI - #9154

Merged
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support
Sep 2, 2026
Merged

fix(grok): health check, model selection, and stop all work against the real CLI#9154
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Grok Build had a cluster of reliability problems that made it feel broken even when the CLI itself was fine:

  • The provider health check opened a full ACP session. authenticate could launch a browser login on its own, and session/new booted every configured MCP server, so background checks hung, timed out, and persisted error over a working install. It also never reported auth state.
  • Picking the built-in Grok Build model failed with unknown model id, because grok-build is the CLI's product name, not a model id its ACP accepts.
  • Stop did not stop. The next message queued behind the old prompt, which kept running to completion.
  • Mid-turn sends queued instead of interrupting like Claude and Codex.

What changed

Health check without a session.grok --version, then grok models for login state and slugs, then a single ACP initialize and reads models from _meta.modelState. No authenticate, no session/new. A failed initialize degrades to warning with the CLI's model list instead of error. XAI_API_KEY counts as authenticated. Against Grok CLI 1.0.13 this returns ready, authenticated, and both models with reasoning options in about 1.2 s.

grok-build means "the session's current model". It is never sent in session/set_model. No hardcoded alias to rot when the next model ships. The mock agent now advertises versioned ids like the real CLI so this cannot regress silently.

Stop actually cancels. This was the root cause behind both stop issues. effect-acp encoded notifications through the Request path, so session/cancel went out as {"id":"","headers":[]}. Grok CLI parses that as a malformed request and drops it. The mock agent was lenient and hid this. Notifications now serialize with no id. Verified live: Stop then a new send answers the new prompt immediately with nothing leaked from the old one. Before this fix the old prompt's output kept streaming into the new turn.

Mid-turn sends interrupt. Takes over #8286 by @mavenskylab with authorship preserved, plus one follow-up that replaces the eight-yieldNow sync loop with a Deferred the ACP runtime settles once the prompt RPC is registered.

Verification

  • Focused tests for the health check parser, model-state builder, product-slug handling, ACP notification encoding, and the existing Grok, Cursor, and ACP runtime suites. 211 passing.
  • Live against Grok CLI 1.0.13: health check snapshot, and stop-then-resend with wire capture of every frame T3 wrote to the agent.

Closes#7746, #5852, #7505, #6075, #8283, #8461.

Written by Claude Fable 5.1 in Claude Code.


Note

Medium Risk
Shared ACP protocol and cancel timing changes affect all ACP-backed providers, not only Grok; Grok steer adds epoch-based concurrency that must stay consistent with interrupt and settlement paths.

Overview
Fixes Grok reliability by aligning probes and turn control with the real CLI, and repairs ACP session/cancel so Grok (and other agents) actually receive cancellation frames.

Provider health check no longer runs authenticate or session/new. It probes grok --version, parses grok models for login state and slugs, then a short ACP initialize to read models from _meta.modelState. Unauthenticated CLIs error with a login hint; failed initialize degrades to warning with CLI-listed models. XAI_API_KEY overrides CLI login for auth reporting.

Model selection: the built-in grok-build slug is T3’s product name—it is never sent in session/set_model; choosing it keeps the session’s current ACP model (reasoning changes still apply to that model). The mock agent advertises versioned ids like production.

Mid-turn sends (steer) on Grok now session/cancel the in-flight prompt, then send the replacement under a prompt epoch / lifecycle semaphore, so new input interrupts like Claude/Codex instead of queueing behind the old prompt.

effect-acp: outbound notifications encode as proper JSON-RPC (no id or headers); RPC Interrupt control messages are dropped. AcpSessionRuntime.cancel awaits the cancel write before completing; prompt can signal dispatched once the prompt RPC is registered for steer races.

Reviewed by Cursor Bugbot for commit 2b9bde5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix Grok health check, model selection, and concurrent turn steering

  • Rewrites checkGrokProviderStatus to probe via ACP initialize only (no session creation), then fall back to grok models CLI output and built-in models; derives auth state from XAI_API_KEY or CLI login text
  • Treats the grok-build product slug as "keep current session model" in applyGrokAcpModelSelection — it is no longer sent through session/set_model; reasoning changes apply to the resolved current model
  • Reworks GrokAdapter.sendTurn with a prompt epoch and lifecycle semaphore so a concurrent turn cancels the active ACP prompt before starting a replacement, skips superseded prompts, preserves the original prompt when replacement prep fails, and emits exactly one terminal event per turn
  • Encodes outbound ACP notifications through encodeJsonRpcNotification without id or headers, and discards @effect/rpc/Interrupt messages so they are not sent to ACP agents
  • Risk: discoverGrokModelsViaAcpInitialize now sends only initialize — any code relying on session creation during discovery will no longer get it; sendNotification encoding failures now surface as ACP protocol parse errors rather than native TypeErrors

Macroscope summarized 2b9bde5.

mavenskylaband others added 6 commits September 1, 2026 18:10
Sending a follow-up on a Grok thread waited behind the in-flight ACP
prompt instead of interrupting like Claude/Codex. A steer now cancels
the current prompt and continues the same turn immediately.
Usage-limit exhaustion was already fixed on main by #8358.
Fixes#8283
Made by Grok 4.6 via the Grok harness.
Discarded and interrupted prompts settled turn state while holding
the prompt-lifecycle lock, so settlement could race interruptTurn
or the next sendTurn. Skip vs start still happens under that lock;
settlement now waits for the thread lock after the permit is released.
Made by Grok 4.6 via the Grok harness.
A failed empty steer advanced discardBeforeEpoch before the replacement
prompt prepared, so the live prompt skipped ACP and settled without
turn.completed. Discard the previous epoch only after prep succeeds.
Made by Grok 4.6 via the Grok harness.
The steer path forked session/prompt and then yielded eight times, hoping
the runtime had registered the RPC fiber before releasing the lifecycle
lock. The runtime now settles a Deferred once the prompt is the active
fiber, and the adapter waits on that or on prompt failure.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… as a model id
The Grok health check opened a full ACP session: initialize, authenticate,
session/new. authenticate can launch a browser login, and session/new
boots every configured MCP server. Background checks hung, timed out,
and persisted an error over a working install. The success branch also
hard-coded auth unknown.
The check now runs grok --version, then grok models for login state and
slugs, then a single ACP initialize and reads models from
_meta.modelState. A failed initialize degrades to warning with the CLI
list instead of error. XAI_API_KEY counts as authenticated.
grok-build is the CLI product name, not a model id its ACP accepts, so
session/set_model rejected it. It now means keep the session current
model and is never sent over the wire. The mock agent advertises
versioned ids like the real CLI so this cannot regress silently.
Closes#7746, #5852, #7505, #6075.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Notifications went out through the generic Request encoder, which added
id: "" and headers: []. Grok CLI parses that as a malformed request and
drops it, so Stop never reached the agent and the old prompt kept
running after the next send. The mock agent was lenient and hid this.
Notifications now serialize as {jsonrpc, method, params} with no id.
The client also stops emitting @effect/rpc/Interrupt frames, which ACP
agents log as Method not found.
Verified against Grok CLI 1.0.13: Stop cancels the running prompt and
the next send starts immediately with no leaked output.
Closes#8283, #8461.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/GrokProvider.test.ts Outdated
@github-actions

github-actionsBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.1 KiB13.3 KiB+172 B (+1.3%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−3 B (−0.0%)7.3 KiB
CodexLive turn WebSocket wire6.2 KiB6.4 KiB+175 B (+2.7%)7.8 KiB
CodexLive turn WebSocket decoded54.7 KiB55.6 KiB+910 B (+1.6%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.4 KiB13.5 KiB+24 B (+0.2%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+10 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.6 KiB6.6 KiB+14 B (+0.2%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.8 KiB0 B (0.0%)66.4 KiB
ClaudeLive turn messages10100 (0.0%)21

Baseline: 8efd4e9 · PR result: 2b9bde5 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Comment threadapps/server/src/provider/Layers/GrokProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
t3dotggand others added 2 commits September 1, 2026 18:23
…ns with Schema
Review follow-ups. A non-zero grok models exit printed help or error
text that could be read as model slugs or a login verdict. Only exit 0
is parsed now. The notification encoder uses Schema.fromJsonString to
satisfy the repo lint rule instead of raw JSON.stringify.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b7f5d8f. Configure here.

Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR makes cross-cutting production changes to Grok health checks, effective model defaults, prompt steering, and shared ACP cancellation/wire behavior. It also adds a static-analysis suppression, so the change requires human review under the configured criteria.

Notes:

  • No code objects were reviewed. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@t3dotgg
t3dotgg merged commit a434677 into mainSep 2, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the t3code/harden-grok-build-support branch September 2, 2026 01:48
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
Hermes model selection sent session/set_model unconditionally, including
when the session was already on the requested model. Grok's ACP fix
(pingdotgg#9154) made the mock agent reject set_model for ids it does not
advertise as switchable, which surfaced the redundancy: selecting the
session's current model failed instead of no-opping.
applyHermesAcpModelSelection now takes the session's current model id
(read from session setup at start, tracked on the session for turns) and
sends set_model only when the selection actually changes the model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QingonqJgq96d3byM5qRh9
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grok provider health check times out because it starts a full ACP session (and every MCP server)

2 participants

@t3dotgg@mavenskylab
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(grok): health check, model selection, and stop all work against the real CLI - #9154

Merged
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support
Sep 2, 2026
Merged

fix(grok): health check, model selection, and stop all work against the real CLI#9154
t3dotgg merged 9 commits into
mainfrom
t3code/harden-grok-build-support

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Grok Build had a cluster of reliability problems that made it feel broken even when the CLI itself was fine:

  • The provider health check opened a full ACP session. authenticate could launch a browser login on its own, and session/new booted every configured MCP server, so background checks hung, timed out, and persisted error over a working install. It also never reported auth state.
  • Picking the built-in Grok Build model failed with unknown model id, because grok-build is the CLI's product name, not a model id its ACP accepts.
  • Stop did not stop. The next message queued behind the old prompt, which kept running to completion.
  • Mid-turn sends queued instead of interrupting like Claude and Codex.

What changed

Health check without a session.grok --version, then grok models for login state and slugs, then a single ACP initialize and reads models from _meta.modelState. No authenticate, no session/new. A failed initialize degrades to warning with the CLI's model list instead of error. XAI_API_KEY counts as authenticated. Against Grok CLI 1.0.13 this returns ready, authenticated, and both models with reasoning options in about 1.2 s.

grok-build means "the session's current model". It is never sent in session/set_model. No hardcoded alias to rot when the next model ships. The mock agent now advertises versioned ids like the real CLI so this cannot regress silently.

Stop actually cancels. This was the root cause behind both stop issues. effect-acp encoded notifications through the Request path, so session/cancel went out as {"id":"","headers":[]}. Grok CLI parses that as a malformed request and drops it. The mock agent was lenient and hid this. Notifications now serialize with no id. Verified live: Stop then a new send answers the new prompt immediately with nothing leaked from the old one. Before this fix the old prompt's output kept streaming into the new turn.

Mid-turn sends interrupt. Takes over #8286 by @mavenskylab with authorship preserved, plus one follow-up that replaces the eight-yieldNow sync loop with a Deferred the ACP runtime settles once the prompt RPC is registered.

Verification

  • Focused tests for the health check parser, model-state builder, product-slug handling, ACP notification encoding, and the existing Grok, Cursor, and ACP runtime suites. 211 passing.
  • Live against Grok CLI 1.0.13: health check snapshot, and stop-then-resend with wire capture of every frame T3 wrote to the agent.

Closes#7746, #5852, #7505, #6075, #8283, #8461.

Written by Claude Fable 5.1 in Claude Code.


Note

Medium Risk
Shared ACP protocol and cancel timing changes affect all ACP-backed providers, not only Grok; Grok steer adds epoch-based concurrency that must stay consistent with interrupt and settlement paths.

Overview
Fixes Grok reliability by aligning probes and turn control with the real CLI, and repairs ACP session/cancel so Grok (and other agents) actually receive cancellation frames.

Provider health check no longer runs authenticate or session/new. It probes grok --version, parses grok models for login state and slugs, then a short ACP initialize to read models from _meta.modelState. Unauthenticated CLIs error with a login hint; failed initialize degrades to warning with CLI-listed models. XAI_API_KEY overrides CLI login for auth reporting.

Model selection: the built-in grok-build slug is T3’s product name—it is never sent in session/set_model; choosing it keeps the session’s current ACP model (reasoning changes still apply to that model). The mock agent advertises versioned ids like production.

Mid-turn sends (steer) on Grok now session/cancel the in-flight prompt, then send the replacement under a prompt epoch / lifecycle semaphore, so new input interrupts like Claude/Codex instead of queueing behind the old prompt.

effect-acp: outbound notifications encode as proper JSON-RPC (no id or headers); RPC Interrupt control messages are dropped. AcpSessionRuntime.cancel awaits the cancel write before completing; prompt can signal dispatched once the prompt RPC is registered for steer races.

Reviewed by Cursor Bugbot for commit 2b9bde5. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix Grok health check, model selection, and concurrent turn steering

  • Rewrites checkGrokProviderStatus to probe via ACP initialize only (no session creation), then fall back to grok models CLI output and built-in models; derives auth state from XAI_API_KEY or CLI login text
  • Treats the grok-build product slug as "keep current session model" in applyGrokAcpModelSelection — it is no longer sent through session/set_model; reasoning changes apply to the resolved current model
  • Reworks GrokAdapter.sendTurn with a prompt epoch and lifecycle semaphore so a concurrent turn cancels the active ACP prompt before starting a replacement, skips superseded prompts, preserves the original prompt when replacement prep fails, and emits exactly one terminal event per turn
  • Encodes outbound ACP notifications through encodeJsonRpcNotification without id or headers, and discards @effect/rpc/Interrupt messages so they are not sent to ACP agents
  • Risk: discoverGrokModelsViaAcpInitialize now sends only initialize — any code relying on session creation during discovery will no longer get it; sendNotification encoding failures now surface as ACP protocol parse errors rather than native TypeErrors

Macroscope summarized 2b9bde5.

mavenskylaband others added 6 commits September 1, 2026 18:10
Sending a follow-up on a Grok thread waited behind the in-flight ACP
prompt instead of interrupting like Claude/Codex. A steer now cancels
the current prompt and continues the same turn immediately.
Usage-limit exhaustion was already fixed on main by #8358.
Fixes#8283
Made by Grok 4.6 via the Grok harness.
Discarded and interrupted prompts settled turn state while holding
the prompt-lifecycle lock, so settlement could race interruptTurn
or the next sendTurn. Skip vs start still happens under that lock;
settlement now waits for the thread lock after the permit is released.
Made by Grok 4.6 via the Grok harness.
A failed empty steer advanced discardBeforeEpoch before the replacement
prompt prepared, so the live prompt skipped ACP and settled without
turn.completed. Discard the previous epoch only after prep succeeds.
Made by Grok 4.6 via the Grok harness.
The steer path forked session/prompt and then yielded eight times, hoping
the runtime had registered the RPC fiber before releasing the lifecycle
lock. The runtime now settles a Deferred once the prompt is the active
fiber, and the adapter waits on that or on prompt failure.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… as a model id
The Grok health check opened a full ACP session: initialize, authenticate,
session/new. authenticate can launch a browser login, and session/new
boots every configured MCP server. Background checks hung, timed out,
and persisted an error over a working install. The success branch also
hard-coded auth unknown.
The check now runs grok --version, then grok models for login state and
slugs, then a single ACP initialize and reads models from
_meta.modelState. A failed initialize degrades to warning with the CLI
list instead of error. XAI_API_KEY counts as authenticated.
grok-build is the CLI product name, not a model id its ACP accepts, so
session/set_model rejected it. It now means keep the session current
model and is never sent over the wire. The mock agent advertises
versioned ids like the real CLI so this cannot regress silently.
Closes#7746, #5852, #7505, #6075.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Notifications went out through the generic Request encoder, which added
id: "" and headers: []. Grok CLI parses that as a malformed request and
drops it, so Stop never reached the agent and the old prompt kept
running after the next send. The mock agent was lenient and hid this.
Notifications now serialize as {jsonrpc, method, params} with no id.
The client also stops emitting @effect/rpc/Interrupt frames, which ACP
agents log as Method not found.
Verified against Grok CLI 1.0.13: Stop cancels the running prompt and
the next send starts immediately with no leaked output.
Closes#8283, #8461.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/GrokProvider.test.ts Outdated
@github-actions

github-actionsBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.1 KiB13.3 KiB+172 B (+1.3%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−3 B (−0.0%)7.3 KiB
CodexLive turn WebSocket wire6.2 KiB6.4 KiB+175 B (+2.7%)7.8 KiB
CodexLive turn WebSocket decoded54.7 KiB55.6 KiB+910 B (+1.6%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.4 KiB13.5 KiB+24 B (+0.2%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+10 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.6 KiB6.6 KiB+14 B (+0.2%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.8 KiB0 B (0.0%)66.4 KiB
ClaudeLive turn messages10100 (0.0%)21

Baseline: 8efd4e9 · PR result: 2b9bde5 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Comment threadapps/server/src/provider/Layers/GrokProvider.ts Outdated
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
t3dotggand others added 2 commits September 1, 2026 18:23
…ns with Schema
Review follow-ups. A non-zero grok models exit printed help or error
text that could be read as model slugs or a login verdict. Only exit 0
is parsed now. The notification encoder uses Schema.fromJsonString to
satisfy the repo lint rule instead of raw JSON.stringify.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b7f5d8f. Configure here.

Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR makes cross-cutting production changes to Grok health checks, effective model defaults, prompt steering, and shared ACP cancellation/wire behavior. It also adds a static-analysis suppression, so the change requires human review under the configured criteria.

Notes:

  • No code objects were reviewed. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment threadapps/server/src/provider/Layers/GrokAdapter.ts
@t3dotgg
t3dotgg merged commit a434677 into mainSep 2, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the t3code/harden-grok-build-support branch September 2, 2026 01:48
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (#8992), sidebar row subscription leases (#9052),
tool group virtualization and scroll anchoring (#9106), repeated-command
and browser-group presentation, inline assistant citations (#9146),
per-cwd provider skills discovery (#8778), Claude composer skill
dispatch (#9128), grok health probe and model negotiation (#9154), and
the failed-tool thinking fallback (#9165).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
Hermes model selection sent session/set_model unconditionally, including
when the session was already on the requested model. Grok's ACP fix
(pingdotgg#9154) made the mock agent reject set_model for ids it does not
advertise as switchable, which surfaced the redundancy: selecting the
session's current model failed instead of no-opping.
applyHermesAcpModelSelection now takes the session's current model id
(read from session setup at start, tracked on the session for turns) and
sends set_model only when the selection actually changes the model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QingonqJgq96d3byM5qRh9
raman325 added a commit to raman325/t3code that referenced this pull request Sep 2, 2026
The mock agent's catalog moved from `grok-build` to `grok-4.6` in pingdotgg#9154;
the Hermes discovery test still asserted the old slug and failed against
current main.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Grok provider health check times out because it starts a full ACP session (and every MCP server)

2 participants

@t3dotgg@mavenskylab